Para el que no lo sepa, Google también funciona como calculadora. Si en la casilla de búsqueda introducis
"5*9*7" os responderá 315. Además funciona para unidades de medida
"100 lb in kg" (45.35 kilo) e incluso da un cambio de divisas
"25 USD in EUR"(unos 20 €, dependiendo del día). Yo lo encuentro muy útil.
A todo esto, recibí un email de Carlos con una referencia de
Blackonion en el que me comentaba que Google no sabe restar y me adjuntaba la explicación. Sí queréis hacer la prueba, buscad la siguiente operación 1-0.9-0.1, que en principio debería dar cero, y la respuesta que os dará es:
Cero! En el mes desde que me lo enviaron (he andado muy liado, no he podido publicarlo antes), lo han corregido, pero antes daba un resultado mucho más interesante. Antes respondía -2.77555756*10
-17 (
el documento de prueba) Obviamente ese resultado no era cero, y se llenaron los blogs de gente diciendo ¡Google no sabe restar! ¡Google falla más que un pentium original! y cosas similares.
Pues bien, resulta que el problema no lo tiene Google, sino muchos otros lenguajes:
# Ruby: 1 - 0.9 - 0.1 = -2.77555756156289e-17
# PHP(4.4): 1 - 0.9 - 0.1 = -2.7755575615629e-17
# JavaScript:1 - 0.9 - 0.1 = -2.7755575615628914e-17
# VbScript: 1 - 0.9 - 0.1 = -2,77555756156289E-17
# Java2: 1 - 0.9 - 0.1 = -2.7755575615628914E-17
# Perl 5: 1 - 0.9 - 0.1 = -2.77555756156289e-017
y todos hacen la operación igual. ¿Porqué?
El standard IEEE 754 (
IEEE = Institute of Electrical and Electronics Engineers, los de las Navidades según Remo) es un método de almacenar números en coma flotante compacto y fácil de usar. Lo utiliza Intel y la mayoría de programas para PC. Se guardan los números en formato binario. Y aquí está la clave de la cuestión.
El 1 se almacena exactamente. Pero algunos números que son sencillos en clave decimal como 0.1 no se pueden grabar de manera exacta en binario. Del mismo modo que 1/3 en decimal se convierte en 0.33333..., el número 1/10 (10 en notación decimal, no
10 binario) se convierte en periodico al ser expresado en binario: 0.1 (decimal) = .0001100011000111000111... (binario).
Como pasa con los números periodicos, el ordenador lo recorta al número de bits máximos que usa, y el número se redondea por 2.78E-17 al ser almacenado (yo aquí también he redondeado ;) ).
Así que el ordenador hace el siguiente cálculo en realidad
1 - 0.9 - (0.1 + 2.78E-17) = -2.78E-17
Y ese resultado tiene mucho más sentido. En Ingeniería computacional esto es muy conocido, y por eso se intenta huir al máximo de operaciones de división del estilo A/(B-C), donde B y C pueden ser muy próximos. Si B-C se acerca a cero, surgen problemas de precisión graves en el resultado y el resultado de la división es aún más sensible a estos errores.
Al fin y al cabo, parece un error muy pequeño, ya que 2.78E-17 =
0.0000000000000000278 y en la calculadora (o el bolsillo) eso no tiene mayor importancia, y si se redondean los resultados (como hace Google ahora) da un cero perfecto. Pero, de momento, ya ha dado para un post sobre
mátematicas.
* He descubierto que se puede reproducir el error cambiando los numeros: