Curiosidades

¿Por qué la suma de decimales no es precisa en los lenguajes de programación?

Lo que todo programador debería saber acerca de la aritmética binaria usada en programación

Así que ha escrito un código absurdamente simple, digamos, por ejemplo:

y obtuve un resultado realmente inesperado:


>>> 0.1 + 0.2
0.30000000000000004
>>>


Esto se debe a que, internamente, las computadoras usan un formato (punto flotante binario) que no puede representar con precisión un número como 0.1, 0.2 o 0.3 en absoluto.

La matemática de coma flotante binaria es así. En la mayoría de los lenguajes de programación, se basa en el estándar IEEE 754. El meollo del problema es que los números se representan en este formato como un número entero multiplicado por una potencia de dos.

¿Por qué pasó esto?

De hecho, es bastante interesante. Cuando tienes un sistema de base 10 (como el nuestro), solo puede expresar fracciones que usan un factor primo de la base. Los factores primos de 10 son 2 y 5. Entonces 1/2, 1/4, 1/5, 1/8 y 1/10 pueden expresarse claramente porque todos los denominadores usan factores primos de 10. En contraste, 1/3, 1/6, 1/7 y 1/9 son decimales periódicos porque sus denominadores usan un factor primo de 3 o 7.

En binario (o base 2), el único factor primo es 2, por lo que solo puede expresar claramente fracciones cuyo denominador tenga solo 2 como factor primo. En binario, 1/2, 1/4, 1/8 se expresarían claramente como decimales, mientras que 1/5 o 1/10 serían decimales repetidos. Entonces 0.1 y 0.2 (1/10 y 1/5), mientras que los decimales limpios en un sistema de base 10, son decimales repetidos en el sistema de base 2 que usa la computadora. Cuando realiza cálculos matemáticos con estos decimales repetidos, termina con sobras que se transfieren cuando convierte el número de base 2 (binario) de la computadora en una representación de base 10 más legible por humanos.

¿Por qué las computadoras usan un sistema tan raro?


No es raro, solo diferente. Los números decimales no pueden representar con precisión un número como 1/3, por lo que tienes que redondear a algo como 0,33, y tampoco esperas que 0,33 + 0,33 + 0,33 sumen 1, ¿verdad?

Las computadoras usan números binarios porque son más rápidos para manejarlos, y porque para la mayoría de los cálculos, un pequeño error en el decimoséptimo lugar decimal no importa en absoluto, ya que los números con los que trabaja no son redondos (ni tan precisos) de todos modos.

¿Por qué otros cálculos como 0,1 + 0,4 funcionan correctamente?


En ese caso, el resultado (0.5) se puede representar exactamente como un número de punto flotante, y es posible que los errores de redondeo en los números de entrada se cancelen entre sí, pero no necesariamente se puede confiar en eso (por ejemplo, cuando esos dos los números se almacenaron primero en representaciones de punto flotante de diferentes tamaños, es posible que los errores de redondeo no se compensen entre sí).

¿Cómo lo resuelvo?

Para Python podemos usar:


x = .1 + .2
#x = 0.30000000000000004

y = float(decimal.Decimal(‘.1’) + decimal.Decimal(‘.2’))
#y = 0.3

Para Javascript se puede utilizar la librería http://mikemcl.github.io/decimal.js/