Cómo se almacena un float
IEEE 754 guarda un número como signo × 1.fracción × 2exponente, es decir, en notación científica binaria. Un float de 32 bits tiene 1 bit de signo, 8 de exponente y 23 de fracción; un double de 64 bits tiene 1, 11 y 52. El exponente se guarda con un sesgo (127 o 1023) para no necesitar su propio bit de signo, y el 1 inicial de la mantisa ni siquiera se almacena, porque en los números normales siempre está ahí.
| Signo | Exponente | Fracción | Sesgo | Dígitos decimales | |
|---|---|---|---|---|---|
| float32 (binary32) | 1 | 8 | 23 | 127 | ~7 |
| float64 (binary64) | 1 | 11 | 52 | 1023 | ~16 |
Por qué 0.1 + 0.2 no es 0.3
0.1 no tiene una expansión binaria finita, igual que 1/3 no la tiene en decimal. El float64 más cercano es 0,1000000000000000055511151231257827…, y 0.2 y 0.3 también quedan ligeramente desviados. Sumar los dos valores redondeados y volver a redondear cae una unidad al lado del float más cercano a 0.3, y por eso la comparación falla. Escribe 0.1 arriba y mira la fila «valor almacenado exacto» para ver el redondeo directamente.
Patrones especiales
- Cero: exponente y fracción todo 0. El bit de signo sigue contando, así que existe −0, que es igual a +0 en las comparaciones.
- Subnormal: exponente todo 0, fracción distinta de cero. Son valores diminutos por debajo del rango normal, con precisión reducida y sin 1 inicial implícito.
- Infinito: exponente todo 1, fracción 0. Surge por desbordamiento y por división entre cero.
- NaN: exponente todo 1, fracción distinta de cero. Surge de 0/0, ∞−∞, sqrt(−1). NaN no es igual a nada, ni siquiera a sí mismo.
Leer los bits a mano
- Divide el patrón en los campos de signo, exponente y fracción.
- Resta el sesgo al exponente para obtener la potencia de dos real.
- Pon «1.» delante de los bits de la fracción (o «0.» para los subnormales) y multiplica por 2 elevado a esa potencia.
Para 0x40490FDB: signo 0, exponente 10000000 = 128 → 128 − 127 = 1, fracción 1.1001001000011111101101 → 1,5707963 × 2 = 3,1415927, el float32 más cercano a π.
Preguntas
¿Cuál es la diferencia entre float y double?
Un float (float32) usa 32 bits y da unos 7 dígitos decimales significativos; un double (float64) usa 64 bits y da unos 16. Los doubles son el valor por defecto en la mayoría de lenguajes (números de JavaScript, floats de Python, double de C); los floats se usan donde importa la memoria o el ancho de banda de la GPU.
¿Por qué el exponente usa un sesgo en vez de complemento a dos?
Con un sesgo, los floats del mismo signo se comparan correctamente como enteros simples: un patrón de bits mayor es un número mayor. Eso hace que ordenar y comparar sea barato en hardware.
¿Qué es el épsilon de máquina?
La distancia entre 1,0 y el siguiente float representable: 2⁻²³ ≈ 1,19 × 10⁻⁷ para float32 y 2⁻⁵² ≈ 2,22 × 10⁻¹⁶ para float64. La distancia crece con el tamaño del número: a partir de 2²⁴, un float32 ya no puede representar enteros impares.
¿Cuál es el mayor entero que un double guarda exactamente?
2⁵³ = 9.007.199.254.740.992. Por encima, ya no todos los enteros consecutivos son representables, por eso JavaScript tiene Number.MAX_SAFE_INTEGER (2⁵³ − 1) y BigInt.
¿Por qué mi lenguaje imprime 0.30000000000000004?
Porque es el decimal más corto que identifica de forma única el double resultante de 0.1 + 0.2. La salida es correcta; es el valor almacenado el que difiere de 0.3.