Coma flotante, un decimal cada vez

Escribe un número decimal. Los pasos que aparecen debajo detallan la conversión tal y como la harías a mano. La línea superior representa lo que el ordenador acaba almacenando.

Cargando simulación interactiva...
Lección

La teoría — Coma flotante291 palabras

Un número en coma flotante es un número entero multiplicado por una potencia de dos: (−1)s × 1.f × 2E−1023. El formato decide cuántos bits corresponden a E y cuántos a f. Esta única división determina tanto el alcance del formato como su precisión para distinguir entre dos números.

Qué significa cada símbolo

s
el bit de signo, 0 para positivo y 1 para negativo. Va por separado en lugar de estar integrado en el número, y por eso el formato tiene un +0 y un −0.
E
el campo del exponente, almacenado con 1023 sumado para poder ser negativo sin necesitar un signo propio. Define en qué rango te encuentras, y el rango es lo que determina la distancia entre dos números vecinos.
f
la fracción: 52 bits que siguen a un 1 inicial que nunca se guarda, puesto que un número normalizado siempre empieza por uno. Esos 52 bits contienen toda la precisión, y el exponente no aporta ninguna.
Supone
Que el número es finito y normal. Por debajo de 2−1022 se descarta el 1 inicial y el formato continúa funcionando a costa de perder precisión, por lo que el valor positivo más pequeño de doble precisión es 4,94 × 10−324 y aporta un solo bit de mantisa.
Falla cuando
En dos partes, ambas en código real. Comparar dos valores calculados con = falla siempre que se llegue a ellos por vías distintas, ya que cada método aplica el redondeo a su manera. Además, una suma larga depende del orden en el que se ejecuta. Suma una lista hacia adelante y luego hacia atrás; verás que los totales difieren. Si añades primero los términos más pequeños, la pérdida es mínima.

Ocho de los mil 🖖

De los números entre 0,001 y 1,000, exactamente ocho se almacenan sin el menor error: 0,125; 0,25; 0,375; 0,5; 0,625; 0,75; 0,875 y 1. Una fracción binaria es la suma de medios, cuartos, octavos y así sucesivamente. Un denominador de 1000 conlleva un factor de 125 que ninguna potencia de dos conseguirá anular. Escribe 0,375 y la herramienta lo marcará como exacto. Escribe 0,376 y ya no lo hará.

0,1 + 0,2 cae exactamente en la mitad 🖖

Los dos valores almacenados suman 0,3000000000000000166533453693773481063544750213623046875, que es el punto medio exacto entre los dos números de doble precisión a cada lado de 0,3. La suma en sí es impecable. Es necesario deshacer el empate de alguna forma, y la regla indica que se debe tomar al vecino cuyo último bit es par. El número por debajo de 0,3 termina su fracción con un bit impar y el que está por encima con uno par, de modo que la suma se redondea hacia arriba. De ahí sale la cola en 0,30000000000000004.

Menos bits, respuesta correcta 🖖

Pulsa binary32 con los mismos dos números. 0,1 + 0,2 da como resultado 0,300000011920928955078125, que es exactamente cómo se almacena 0,3 en ese formato. El famoso fallo requiere que la suma caiga en un empate, y en 24 bits se queda a un cuarto de salto de lograrlo, por lo que se redondea de vuelta al número que esperabas. La mitad de precisión, y la respuesta que querías.

El salto se duplica en cada potencia de dos 🖖

En cualquier punto entre 0,0625 y 0,125, la distancia de un número representable al siguiente es de 1,39 × 10⁻¹⁷, y no varía en absoluto dentro de ese intervalo. Pasa al siguiente intervalo superior y se duplicará. La escalera de la gráfica es exactamente eso, un escalón por cada potencia de dos, razón por la cual un mismo formato puede almacenar 10⁻³⁰⁰ y 10³⁰⁰ pero no puede retener 9007199254740993.

Problema resuelto al detalle

  1. Un sistema de pagos almacena importes en libras usando binary64. Demuestra que tanto 0,10 £ como 0,20 £ se guardan con un valor ligeramente alto, que su suma no da 0,30 £ y explica cómo lo soluciona un ingeniero de pagos.

    Abre este problema en la herramienta

    1. 0,1 en base dos es 0,0001 seguido de 1001 que se repite infinitamente. Una décima necesita un cinco en su denominador, pero una fracción binaria solo tiene doses, por lo que el desarrollo nunca se cierra.

    2. Se conservan 53 dígitos binarios y los demás se eliminan por redondeo. En este caso se redondean hacia arriba, por lo que el valor almacenado supera a 0,1 en 5,55 × 10⁻¹⁸. El paso de redondeo en la página ilustra esta dirección con una flecha.

    3. 0,2 tiene esos mismos 53 dígitos con el exponente incrementado en uno, por lo que su error es exactamente el doble: 1,11 × 10⁻¹⁷. Introduce 0,2 en la casilla y compara las dos tarjetas de error.

    4. Al sumarlos, los dos valores almacenados caen exactamente en el punto medio entre los dos doubles situados a cada lado de 0,3. En caso de empate, se elige al vecino que termina en un bit par, que es el número superior.

    5. Así que lo que se obtiene es 0,3000000000000000444089209850062616169452667236328125, y cualquier cálculo posterior arrastrará este valor.

    6. Ahora teclea 10 y 20 en lugar de 0,1 y 0,2. Ambos son números enteros muy inferiores a 2⁵³, los dos se representan con exactitud, y 10 + 20 da 30 sin perder nada en el proceso.

    Respuesta

    Almacena el dinero como un número entero de la unidad más pequeña, peniques en lugar de libras, y la aritmética será exacta porque cada número entero hasta 2⁵³ es exacto. El único redondeo que queda es el que escribes tú mismo, en el momento que eliges, ahí donde puedes verlo claramente. La herramienta te muestra ambas partes en diez segundos: teclea 0,1 y la tarjeta de error no es cero, teclea 10 y sí lo es.