Abre el navegador en el ordenador, pulsa F12 para abrir la consola, escribe 0.1 + 0.2 y pulsa Enter. La respuesta es 0.30000000000000004. Prueba en Python: lo mismo. Una máquina hecha para calcular falla una suma de primaria.

La pregunta tonta de esta lección es: ¿por qué el ordenador dice que 0,1 + 0,2 no es 0,3? No está roto. Guarda los números de una manera en la que 0,1 no cabe exacto. Esta lección explica cuál es esa manera, por qué casi nunca se nota y cuándo sí.

Elige tu carta: ♣ si empiezas de cero, ♦ si no te asusta una fórmula sencilla, ♠ si quieres la notación. Puedes cambiarla en cualquier momento.

Nivel de explicación

0,1 no cabe en binario

Nivel de explicación

Novato

Intenta escribir un tercio con decimales: 0,3333… Por muchas cifras que pongas, nunca llegas, siempre falta un poco. El número no tiene nada de raro. Lo que pasa es que en decimal, que cuenta en décimas, centésimas y milésimas, un tercio no tiene final.

El ordenador no cuenta en décimas: cuenta en mitades. Mitades, cuartos, octavos, dieciseisavos… Cada trozo es la mitad del anterior. Y con trozos así, una décima tampoco tiene final: te acercas muchísimo, pero siempre falta un trocito.

Como el ordenador solo tiene sitio para unas cuantas decenas de trozos, corta ahí y se queda con lo más cercano. Su 0,1 no es 0,1: es un pelín más. Su 0,2 también se pasa un pelín, y su 0,3 se queda un pelín corto. Al sumar, esos pelines no cuadran, y sale 0,30000000000000004.

Intermedio

El ordenador guarda los números en binario, solo con ceros y unos. En decimal, cada cifra después de la coma vale la décima parte que la anterior: décimas, centésimas… En binario, cada cifra vale la mitad que la anterior: ½, ¼, ⅛, 1/16…

Para escribir 0,1 en binario hay que ver qué trozos caben: ½ no, ¼ no, ⅛ no, 1/16 sí… Sale 0,0001100110011…, y el grupo 0011 se repite para siempre. Con nueve cifras llegas a 0,099609375; con más te acercas, pero nunca terminas. Le pasa lo mismo que a 1/3 en decimal.

Un ordenador normal guarda 53 cifras binarias y redondea al número más cercano que puede escribir con ellas. Su 0,1 vale exactamente 0,1000000000000000055511151231257827021181583404541015625, un poco más que 0,1 (tutorial de Python).

Con 0,2 y 0,3 pasa lo mismo, cada uno con su pequeño error. La suma de los dos primeros no cae en el número que el ordenador usa para 0,3, sino en el siguiente: 0,30000000000000004.

Técnico

♦ → ♠ Del intermedio al técnico
En ♦ decíamosEn ♠ se escribe
binariobase 2; (·)₂ marca un número escrito en base 2
el grupo 0011 se repite para siempre0,0(0011)₂ = Σₖ≥₁ (2⁻⁴ᵏ + 2⁻⁴ᵏ⁻¹), desarrollo periódico
Le pasa lo mismo que a 1/3 en decimalp/q ∈ ℚ (racional) irreducible: desarrollo finito en base 2 ⇔ q = 2ᵏ
53 cifras binariasprecisión p = 53 bits
redondea al número más cercanofl(x): redondeo al más cercano, con los empates al par
La sumax ⊕ y = fl(x + y), la suma en coma flotante
el siguienteel vecino a un ulp (unit in the last place), aquí 2⁻⁵⁴

Una fracción irreducible p/q tiene desarrollo finito en base 2 solo si q es potencia de 2. 1/10 lleva un 5 en el denominador y queda periódico: 0,1 = 0,0(0011)₂ = Σₖ≥₁ (2⁻⁴ᵏ + 2⁻⁴ᵏ⁻¹). La serie geométrica lo confirma: (3/32) / (15/16) = 1/10.

Con p = 53, fl(0,1) es la fracción J/2ᴺ más cercana con J de 53 bits: J = 7205759403792794 y N = 56, que simplificada queda 3602879701896397 / 2⁵⁵ (tutorial de Python). Como 10 × 3602879701896397 = 36028797018963970 y 2⁵⁵ = 36028797018963968:

fl(0,1) − 0,1 = 2 / (10 · 2⁵⁵) = 1 / (5 · 2⁵⁵) ≈ 5,55×10⁻¹⁸

Se redondeó hacia arriba. En 0,1 ⊕ 0,2, la suma exacta fl(0,1) + fl(0,2) cae justo a medio camino entre dos números de 53 bits. La regla de empates al par la manda al de arriba, que está un ulp, 2⁻⁵⁴ ≈ 5,55×10⁻¹⁷, por encima de fl(0,3). Por eso 0.1 + 0.2 == 0.3 es falso en Python, en JavaScript y en cualquier lenguaje que use este formato (cálculo propio con aritmética exacta; en JavaScript, 0.1 + 0.2 - 0.3 da 2⁻⁵⁴).

El ordenador suma bien lo que tiene. El problema es que lo que tiene no es 0,1: no le cabe.

Coma flotante: notación científica en binario

Nivel de explicación

Novato

En la lección de números enormes viste la notación científica: 7×10²⁷ es un 7 con 27 ceros detrás. Sirve para escribir números enormes y diminutos con pocas cifras.

El ordenador hace lo mismo, pero en binario y siempre con el mismo número de cifras: unas 16 cifras decimales. Se llama coma flotante porque la coma “flota”: se mueve según lo grande o lo pequeño que sea el número, y las cifras son siempre las mismas.

Imagina una regla con un número fijo de marcas. Cerca del cero, las marcas están muy juntas y puedes medir cosas pequeñas con mucho detalle. Lejos del cero, están cada vez más separadas. Si lo que mides cae entre dos marcas, apuntas la más cercana: eso es redondear.

Con 16 cifras, la regla es finísima: el 0,1 se desvía menos de una parte en diez mil billones. Por eso casi nunca se nota.

Intermedio

Un número en coma flotante se guarda en tres partes, como en notación científica pero en base 2:

  • el signo, + o −;
  • el exponente, que dice por qué potencia de 2 se multiplica;
  • la mantisa, que son las cifras.

El formato normal se llama binary64 (o “doble precisión”): 64 bits, 1 de signo, 11 de exponente y 52 de mantisa (MDN; NumPy). La mantisa empieza siempre por un 1 que no hace falta guardar, así que tiene 53 cifras binarias, unas 16 decimales. Es el formato de los números de JavaScript, de los float de Python y de Excel. Por ejemplo, 0,1 = + 1,6 × 2⁻⁴.

Como hay siempre las mismas cifras, la separación entre dos números seguidos crece con el tamaño. Justo por encima de 1 es de 2,2×10⁻¹⁶. Junto a 10¹⁶ es de 2, y por eso 10¹⁶ + 1 da 10¹⁶. Por lo mismo, los números enteros solo son exactos hasta unos 9×10¹⁵ (MDN).

Algunas combinaciones de bits se reservan para el cero, el infinito y los resultados sin sentido, como la raíz cuadrada de −1 (Microsoft, sobre Excel).

Cuando el resultado de una operación cae entre dos números que se pueden guardar, se redondea al más cercano. Cada redondeo se equivoca, como mucho, en media separación: menos de una parte en 9×10¹⁵.

Técnico

♦ → ♠ Del intermedio al técnico
En ♦ decíamosEn ♠ se escribe
signos ∈ {0, 1}
exponenteE, de 11 bits, con sesgo 1023: el exponente real es E − 1023
mantisa(1.f)₂, con f los 52 bits guardados y el 1 implícito
binary64formato de IEEE 754-2019 con p = 53, emin = −1022 y emax = 1023
la separación entre dos números seguidosulp(x) = 2^(⌊log₂|x|⌋ − 52), con ⌊·⌋ la parte entera por abajo
se redondea al más cercanofl(x) = x(1 + δ), |δ| ≤ u = 2⁻⁵³ (u: unidad de redondeo)
Justo por encima de 1 es de 2,2×10⁻¹⁶ε = ulp(1) = 2⁻⁵² (Number.EPSILON, sys.float_info.epsilon)
el infinito y los resultados sin sentido±∞ y NaN (not a number), con E = 2047; E = 0, para el cero y los subnormales

Un binary64 normal vale x = (−1)ˢ · (1.f)₂ · 2^(E − 1023), con 1 ≤ E ≤ 2046. Los valores E = 0 y E = 2047 se reservan para el cero, los subnormales (sin el 1 implícito), ±∞ y NaN. Los parámetros p = 53, emin = −1022 y emax = 1023 son los de la tabla D-1 de Goldberg (1991); la revisión actual del estándar es IEEE 754-2019.

Entre 2ᵉ y 2ᵉ⁺¹ hay 2⁵² números igualmente espaciados, separados ulp(x) = 2^(⌊log₂|x|⌋ − 52). Con redondeo al más cercano, fl(x) = x(1 + δ) con |δ| ≤ u = 2⁻⁵³, y cada operación básica cumple lo mismo: x ⊕ y = (x + y)(1 + δ) (Goldberg).

Cuidado con los nombres. MDN, Python y PyTorch llaman épsilon a ε = 2⁻⁵² = ulp(1), la distancia de 1 al siguiente número. Goldberg llama machine epsilon a la cota del error relativo, que es la mitad: u = 2⁻⁵³. Los enteros son exactos hasta 2⁵³ = 9 007 199 254 740 992; desde ahí, ulp ≥ 2 (MDN, Number.MAX_SAFE_INTEGER = 2⁵³ − 1).

El redondeo se acumula

Nivel de explicación

Novato

Imagina una báscula de camiones un poco especial: no vuelve a pesarlo todo, sino que suma lo que subes al número que ya marca y redondea al kilo. Encima hay un camión de 10 000 kilos, y tienes mil plumas que juntas pesan un kilo. Subes una pluma: la báscula sigue en 10 000. Otra: 10 000. Las mil, una a una: 10 000, porque cada vez redondea al kilo y una pluma sola no llega. Ahora mete las mil plumas en una bolsa y súbela de golpe: 10 001.

Al ordenador le pasa lo mismo. Cada suma redondea, y los errores pequeños se acumulan o se pierden según el orden en que sumes. Si sumas 0,1 diez veces seguidas, no da 1: da 0,9999999999999999.

Casi siempre da igual, porque el error es diminuto. Pero si comparas el resultado con 1 para decidir algo, la respuesta es “no son iguales”. Por eso, con números con decimales, los programadores no preguntan “¿son iguales?”, sino “¿están muy cerca?”.

Intermedio

Cada operación redondea, y los errores se van acumulando. Al sumar 0,1 en un bucle, en JavaScript:

VecesResultado
30,30000000000000004
80,7999999999999999
100,9999999999999999
10 0001000,0000000001588

Además, el orden cambia el resultado. Sumar un número pequeño a uno muy grande puede no cambiar nada (10¹⁶ + 1 = 10¹⁶), así que (a + b) + c no siempre da lo mismo que a + (b + c) (Goldberg, 1991).

Tres remedios habituales:

  • Comparar con tolerancia, en vez de con ==. En Python, math.isclose(0.1 + 0.1 + 0.1, 0.3) da True (tutorial de Python).
  • Sumar con cuidado. math.fsum lleva la cuenta de las cifras que se pierden y redondea una sola vez. Y desde Python 3.12, sum() compensa los errores por dentro: sum([0.1] * 10) == 1.0 da True en casi todas las instalaciones, mientras que el bucle a mano da 0,9999999999999999.
  • Redondear al mostrar, no al calcular: dos decimales para un precio.

Técnico

♦ → ♠ Del intermedio al técnico
En ♦ decíamosEn ♠ se escribe
Cada operación redondeax ⊕ y = fl(x + y), y x ⊖ y = fl(x − y)
los errores se van acumulandosuma recursiva s ← s ⊕ xⱼ: el sumando j se perturba hasta (n − j)u
el orden cambia el resultado⊕ es conmutativa pero no asociativa
Comparar con tolerancia|a − b| ≤ max(rel_tol · max(|a|, |b|), abs_tol), con rel_tol = 10⁻⁹ (math.isclose)
Sumar con cuidadosuma compensada de Kahan, con c el error que arrastra cada paso
compensa los errores por dentrosuma de Neumaier, una variante de la de Kahan (gh-100425)
redondea una sola vezun único redondeo al final (math.fsum); O(nu²): términos del orden de nu² o menores

En la suma recursiva, cada sumando xⱼ entra con un factor (1 + δⱼ), con |δⱼ| < (n − j)u: el error crece con n (Goldberg, 1991, que llama épsilon a u = 2⁻⁵³, como se vio en el bloque anterior). La suma compensada de Kahan guarda en c lo que ha perdido cada ⊕ y lo devuelve en el paso siguiente. Su error queda en (2u + O(nu²)) Σ|xⱼ|, casi sin depender de n (Goldberg, teorema 8; Kahan, CACM 8, 40, 1965).

Sin asociatividad, el orden importa: (10³⁰ ⊕ −10³⁰) ⊕ 1 = 1, pero 10³⁰ ⊕ (−10³⁰ ⊕ 1) = 0 (Goldberg). Una consecuencia: repartir una suma larga entre varios procesadores cambia el orden, y el resultado puede variar en las últimas cifras.

Para comparar, math.isclose(a, b) comprueba |a − b| ≤ max(rel_tol · max(|a|, |b|), abs_tol), con rel_tol = 10⁻⁹ por defecto: unas 9 cifras de acuerdo (documentación de Python). sum() usa la suma de Neumaier desde Python 3.12 (gh-100425) y math.fsum hace un solo redondeo al final.

Nunca preguntes a un número con decimales si es igual a otro. Pregúntale si está muy cerca.

Menos bits para la IA, decimales para el dinero

Nivel de explicación

Novato

No todos los números necesitan 16 cifras. Una red neuronal, como las que hay detrás de un traductor automático, hace muchísimas multiplicaciones con millones de números. Si cada número ocupa la mitad, caben el doble en memoria y las cuentas pueden ir más rápido. A cambio, cada número es más basto, como una foto con menos píxeles.

Con 16 bits, el ordenador solo tiene unas 3 cifras. Si sumas 0,1 una y otra vez, al llegar a 256 la suma se queda atascada: 0,1 es menos que media separación entre dos marcas de la regla, y se redondea a nada. Lo verás en el widget de abajo.

Con el dinero pasa al revés: no queremos ni un céntimo de error. Para el dinero se recomienda no usar estos números con decimales en binario, sino contar en céntimos, con números enteros, que se guardan exactos, o usar cuentas en decimal, como hacemos las personas.

Intermedio

Además de binary64 hay formatos más pequeños:

  • float32, 32 bits (1 + 8 + 23): unas 7 cifras.
  • float16, 16 bits (1 + 5 + 10): unas 3 cifras, y nada por encima de 65 504.
  • bfloat16, 16 bits (1 + 8 + 7): solo unas 2 cifras, pero el mismo rango que float32. Lo pensaron en Google para el aprendizaje automático (blog de Google Cloud, 2019).

Las redes neuronales usan mucho estos formatos pequeños: ocupan la mitad de memoria y pueden ir más rápido. El truco se llama precisión mixta: hacer las multiplicaciones en 16 bits y guardar una copia de los pesos de la red en 32. En float16, un cambio pequeño puede perderse si el número al que se suma es 2048 veces mayor o más (Micikevicius et al., 2018). Es la báscula de camiones otra vez.

Para el dinero se hace lo contrario: aritmética decimal, que cuenta en décimas y centésimas como nosotros, o enteros de céntimos. En decimal, 0,1 + 0,1 + 0,1 − 0,3 da exactamente 0; en binario, 5,55×10⁻¹⁷ (documentación del módulo decimal de Python, pensado para contabilidad).

Técnico

♦ → ♠ Del intermedio al técnico
En ♦ decíamosEn ♠ se escribe
unas 7 cifrasp · log₁₀2 cifras decimales: 7,22 con p = 24
nada por encima de 65 504máximo finito (2 − 2¹⁻ᵖ) · 2^emax, con emax el mayor exponente
el mismo rango que float32el mismo exponente de 8 bits: emax = 127
precisión mixtamixed precision: productos en FP16 o BF16 (float16, bfloat16); pesos maestros y acumulación en FP32 (float32)
los pesos de la redpesos w; gradiente: cuánto cambia la pérdida (el error de la red) al mover cada peso
GoogleTPU (Tensor Processing Unit): el chip de Google para redes neuronales
un cambio pequeño puede perdersew ⊕ Δw = w si |Δw| < ulp(w)/2
2048 veces mayor2¹¹ = 2ᵖ con p = 11
aritmética decimalcoma flotante en base β = 10 (módulo decimal de Python)

Con p bits de precisión y exponente máximo emax, ε = 2¹⁻ᵖ y el máximo finito es (2 − 2¹⁻ᵖ) · 2^emax. Los bits salen de NumPy, PyTorch y Google; los valores de la tabla son cálculo propio. Para binary16, (2 − 2⁻¹⁰) · 2¹⁵ = 65 504, el mismo valor que dan Micikevicius et al. (2018).

w ⊕ Δw = w en cuanto |Δw| < ulp(w)/2, y en FP16 eso puede pasar desde |w| ≥ 2¹¹|Δw| (Micikevicius et al.). Su receta de precisión mixta guarda los pesos maestros en FP32, multiplica en FP16 y escala la pérdida para que los gradientes pequeños no caigan a cero: en FP16 no hay ningún número positivo por debajo de 2⁻²⁴, y en su detector de objetos (SSD) bastó con un factor 8. En las TPU de Google, cada multiplicación de matrices multiplica en bfloat16 y acumula en FP32 (Google Cloud, 2019). El widget lo enseña con 0,1: en float16, desde 256 el ulp es 0,25 y 0,1 < 0,125.

El módulo decimal de Python es coma flotante en base 10: 0,1 se guarda exacto y 0,1 + 0,1 + 0,1 − 0,3 da 0. Para dinero también valen los enteros de céntimos, exactos en binary64 hasta 2⁵³.

Prueba tú: suma 0,1 una y otra vez

Elige cómo guarda los números el ordenador y cuántas veces suma 0,1. Compara lo que da con lo que debería dar y mira cómo crece el error en la gráfica. Prueba float16 con 5000 veces.

Suma 0,1 una y otra vezGráfica del error relativo frente al número de veces que se suma 0,1, las dos en escala logarítmica, con una curva por formato: binary64, float32, float16 y bfloat16. Al empezar, binary64 y 10 veces: debería dar 1 y da 0,9999999999999999.10⁰10⁻⁴10⁻⁸10⁻¹²10⁻¹⁶110100100010⁴veces que sumas 0,1error relativo

Una curva por formato; la del elegido, en grueso.

Cómo guarda los números
10 veces
Debería dar
1
Da
0,9999999999999999
Error
1,1×10⁻¹⁶
Así se guarda 0,1
0,1000000000000000055511151231257827021181583404541015625

Se desvía 1,1×10⁻¹⁶: una parte entre 9×10¹⁵.

Reto final

¿Por qué el ordenador no puede guardar 0,1 exacto?
Sumas 0,1 diez veces en un bucle y compruebas si el resultado es igual a 1. ¿Qué pasa?
Para guardar el saldo de una cuenta bancaria, ¿qué es mejor?

En tres frases

  1. El ordenador cuenta en binario, y en binario 0,1 no tiene final, como 1/3 en decimal: se guarda redondeado, un pelín por encima.
  2. La coma flotante es notación científica en binario con cifras fijas (unas 16 en binary64): cada operación redondea, el error se acumula y el orden de las sumas importa.
  3. Por eso los números con decimales se comparan con tolerancia; la IA usa formatos de 16 bits porque ahorran memoria, y el dinero va en céntimos enteros o en decimal.

Fuentes

Cómo está hecha esta lección: investigada y redactada con ayuda de Claude a partir de las fuentes de arriba, comprobadas y contrastadas con una segunda fuente el 15 de octubre de 2026. Los resultados de sumar 0,1 en un bucle, en cada formato, se midieron en JavaScript (Node 24) y los comprueba un test; las cifras sin enlace propio son cálculos a partir de las fuentes. Los dibujos son propios.