Mucho se ha dicho por todas las esquinas de la blogósfera acerca de este bug en Excel. Sin embargo, pocos son los que se pusieron a investigar o explicar qué es lo que está mal. Lo que es más, muchos inclusive se ríen de que MS no sabe multiplicar… cuando no es así en lo más mínimo.
He aquí una traducción de la explicación de dónde está el problema
Notas de Traducción
- Esta es una traducción, el artículo fue escrito por Joel Spolsky
- No pretendo defender a MS ni mucho menos… pero las cosas se tienen que decir como son
- Se utilizará el formato de números que utiliza el punto como separador de miles y como lo que debería ser la “coma decimal” en español
- Los enlaces se mantuvieron iguales que en el artículo original así que seguramente llevarán a contenido en inglés
- Artículo original: Explaining the Excel Bug
La Traducción
Probablemente hayan visto mucha alharaca acerca del bug en la más reciente versión de Excel: 2007. Básicamente, multiplicar 77.1 por 850, que debería dar 65.535 en realidad muestra 100.000.
Antes de intentar explicar esto, deberían de saber que trabajé en el equipo de Excel, pero fue trece años atrás. Hace mucho tiempo que no estoy allí. No creo que quede alguien que me conozca allí todavía y sólo estoy intentando explicar el error como un poco de servicio a la comunidad.
Lo primero que tienen que entender es que Excel mantiene los números internamente en formato binario pero los muestra como texto (cadenas). Por ejemplo, al tipear 77.1 Excel lo guarda internamente utilizando 64 bits:
0100 0000 0101 0011 0100 0110 0110 0110
0110 0110 0110 0110 0110 0110 0110 0110
La pantalla muestra cuatro caracteres: “7″, “7″, “.” y “1″.
En algún lugar dentro de Excel existe una función que convierte números binarios a cadenas para mostrar. Éste es el código que tiene el error que causa que unos pocos números extremadamente cercanos a 65.535 sean mostrados incorrectamente como 100.000
Si se utiliza el número en otros cálculos, por ejemplo sumando dos al resultado, será el correcto.
=77.1*850 muestra 100000
=77.1*850+2 muestra 65537 correctamente
Sólo para los chismosos, este error también es para un par de números extremadamente cercanos a 65.536. Éstos son mostrados incorrectamente como 100.001.
=77.1*850+1 muestra 100001
Éste es, sin embargo, un error en el código encargdo de mostrar el número. Si haces un gráfico con esa celda, será el correcto.
Ahora… habrán observado que mencioné que este error existe para números que están extremadamente cerca de 65.535 pero no para el mismo 65.535. De hecho, si introducimos 65.535 se mostrará correctamente ¡Pero 77.1 * 850 es exactamente 65.535 y no “extremadamente cerca” a 65.535!
Veamos más de cerca la representación binaria de 77.1:
0100 0000 0101 0011 0100 0110 0110 0110
0110 0110 0110 0110 0110 0110 0110 0110
¿Ven la cantidad de 0110? Eso es porque 0.1 no tiene una representación exacta en binario… es un número binario periódico. De la misma forma que 1/3 es 0.33333…. y hay que seguir con 3’s para siempre. Si no tenemos tanta paciencia, el número no es exacto.
Podemos imaginarnos ahora como, en decimal, si intenáramos hacer 3 por 1/3 y no escribiéramos todos los 3s, el resultado sería 0.9999… y no 1. Y la gente se enojaría por un resultado erróneo.
Lo mismo sucede con los números binarios que terminan en 0.1: tienen infinitos decimales. Y al operar matemáticamente con ellos los errores pequeños e insignificantes se propagan muy lejos de la coma decimal (PD: lo mismo sucede para .2, .3, .4, .6, .7, .8 y .9 pero no para .5).
El IEEE tiene un estándar, IEEE 754, que indica cómo representar números de punto flotante en binario que es lo que casi todo el munod utiliza… incluyendo Excel. Y lo han hecho por mucho tiempo y significa que a veces se obtienen resultados imprecisos al agregar muchos 0.1’s juntos; pero si se redondean los números a una cantidad razonable de posiciones decimales no es algo de lo que haya que preocuparse.
Volviendo al bug en Excel, que es un bug genuino y no una artimaña del estándar IEEE 754. Como 77.1 no tiene una representación exacta, Excel lo guarda como:
0100 0000 0101 0011 0100 0110 0110 0110
0110 0110 0110 0110 0110 0110 0110 0110
y cuand lo multiplicamos por 850, obtenemos algo muy cercano a 65.535 pero no exactamente 65.535 por el simple hecho que 77.1 no fue guardado exactamente (porque ocuparía infinita memoria). Y éste número, muy cercano a 65.535 es casualmente uno de los 12 posibles números en punto flotante que sufren de este bug en Excel.
Preguntas y Respuestas
Pregunta: ¿No es esto muy, muy malo?
Respuesta: En mi opinión, no. La posibilidad de que veas esto en cálculos reales es microscópica. Más vale preocuparse por que nos pegue un meteorito. Microsoft, obviamente, se ve forzada a decirle a todos que “la precisión es extremadamente importante para nosotros” y seguramente lo resolverán en unos días. Serán objeto de todo tipo de bien merecidas ridiculizaciones pero como no trabajo allí puedo decirles que la posibilidad de que realmente te importe este bug es ridículamente chica.
Pregunta: ¿No deberían de verificar este tipo de cosas?
Respuesta: Apostaría que la mayoría de las pruebas numéricas de Excel son hechas automáticamente con código VBA. Las celdas conteniendo el valor serán mostradas como 100.000; pero desde VBA, son 65.535 (ya que el número sería pasado al entorno de ejecución de Basic en su forma binaria antes de darle formato para visualizarlo). Estoy seguro que hay mucho código para probar los formatos de visualización; pero un bug como este que sólo sucede en 12 de 18446744073709551616 posibles números binarios en punto flotante es poco probable que un conjunto de tests de caja negra los cubra.
Pregunta: ¿Qué causó el bug?
Respuesta: No estoy seguro ya que no tengo el código. No se me ocurre nada que podría llegar a causar este comportamiento. Jugando con la calculadora IEEE-754 de Quanfei Wen podrían llegar a encontrar algo.
Pregunta: ¿Por qué no usar aritmética “exacta” (decimal)?
Respuesta: Es muchísimo más lenta que la aritmética de punto flotante ya que no hay hardware en el chip de la PC que lo haga nativamente
En estos años, Microsoft obtuvo tantas quejas sobre las artimañas en redondeos de punto flotanteen la calculadora de windows que la reescribieron utilizando una biblioteca de aritmética de precisión arbitraria. Como hay que usar la calculadora de windows a la velocidad de un caracol, no tiene porqué ser tan rápida como Excel. Dicho esto, las CPUs se han hecho bastante rápidas. Seugor que una versión de precisión arbitraria de Excel se comportaría bastante bien en estos días. Sin embargo, el equipo de Excel ha pasado 20 años defendiendo IEEE 754, no es raro que le empiecen a creer.
Y sincerémosnos: ¿realmente queremos que las mentes brillantes que trabajan allí y se las arreglen para romper mucho código que anda bien reescribiendo el corazón del motor de cálculos de Excel? Mejor que se ocupen de agregar y sacar clips bailarines durante todo el día.
Wow… que buen artículo. Tiene de todo, matemática binaria, testing, filosofía de empresa, probabilidad. Uno de los mejores que leí en mucho tiempo. ¡Gracias Mati!
En cierta forma coincido con Joel, hay veces que es mucho más costosa alcanzar la exactitud que el costo que nos ocaciona una relativa aproximación, hay que saber balancear la ecuación.
Al igual que en la seguridad informática. Seguridad infinita sugiere costos infinitos. Hay que saber medir y hay que saber hacer participar al objetivo en nuestras decisiones.
Gracias de nuevo Mati, una joyita.
¿Y te pareció interesante perder todo ese tiempo traduciendo un artículo y explicando algo que de cualquier forma no podrías corregir porque el código es cerrado?
Si lo mismo hubiera ocurrido en Openoffice.org, cualquiera con tu conocimiento podría haber encontrado la línea de código y modificarla para que haga lo que debe hacer.
¡Software libre para una sociedad libre!
Saludos