Los números de punto flotante no son reales
Autor: Chuck Allison

Los números de punto flotante no son “números reales” en el sentido matemático, a pesar de que son llamados reales en algunos lenguajes de programación, como Pascal y Fortran. Los números reales tienen una precisión infinita y son, por lo tanto, continuos y sin pérdidas; los números de punto flotante tiene precisión limitada, por lo que son finitos, y son recordados como enteros “con mal comportamiento”, porque no son están espaciados uniformemente a través de su espacio de distribución.

Para ilustrarlo, asigna 2147483647 (el número más grande en un entero de 32 bits) a una variable float de 32 bits (digamos x) e imprímelo. Verás 2147483648. Ahora imprime x - 64. Aún 2147483648. Ahora calcula x - 65 y ¡obtendrás 2147483520! ¿Por qué? Porque la separación entre flotantes adyacentes en ese rango es de 128 y las operaciones de punto flotante se redondean al punto flotante más cercano.

Los números de punto de flotante de la IEEE son números de precisión fija basados en notación científica de base 2: 1.d1d2…dp-1 x 2e, donde p es la precisión (24 para float, 53 para double). El espaciamiento entre dos números consecutivos es 21-p+e, lo cual puede ser aproximado con seguridad a ε|x|, donde ε es el épsilon de la máquina (21-p).

Conocer el espaciamiento en los vecinos de un número de punto flotante puede ayudarte a evitar errores numéricos clásicos. Por ejemplo, si estás realizando un cálculo iterativo, como buscar la raíz de una ecuación, no tiene sentido buscar una precisión más grande que el sistema numérico puede darte en la cercanía de la respuesta. Asegúrate que la tolerancia que pides no es menor que el espaciado ahí; de otro modo harás un bucle infinito.

Debido a que los números de punto flotante son aproximaciones de los números reales, inevitablemente hay un pequeño error presente. Este error, llamado redondeo, puede llevarnos a errores sorpresivos. Por ejemplo, cuando sustraes números cercanamente iguales, los dígitos más significativos se cancelan entre sí, entonces lo que era el dígito menos significativo (donde reside el error de redondeo) es promovido a la posición más significativa en el resultado de punto flotante, contaminando esencialmente cualquier cómputo relacionado (un fenómeno conocido como smearing). Necesitas mirar muy de cerca tus algoritmos para prevenir esa cancelación catastrófica. Para ilustrarlo, considera resolver la ecuación x2 - 100000x + 1 = 0 con la fórmula cuadrática. Como los operandos en la expresión -b + sqrt(b2 - 4) son cercanamente iguales en magnitud, puedes en su lugar computar la raíz r1 = -b - sqrt(b2 -4), y entonces obtener r2 = 1/r1, como en cualquier ecuación cuadrática, ax2 + bx + c = 0, entonces la raíz satisface r1r2 = c /a.

El smearing puede ocurrir incluso en formas más sutiles. Supón una librería que ingenuamente computa ex con la fórmula 1 + x + x2/2 + x3/3! + … Esto funciona bien para una x positiva, pero considera qué pasa cuando x es un número negativo grande. Los términos impares potenciados resultan en un número positivo grande y sustrayendo las magnitudes de pares potenciados ni se verán afectados en el resultado. El problema aquí es que el redondeo en los grandes términos positivos está a un dígito de posición de la más grande significancia que la verdadera respuesta. ¡La respuesta difiere hacia positivo infinitamente! La solución aquí también es simple: para una x negativa, computa ex = 1/ e|x|.

No podemos irnos sin decir que no deberías usar números de punto flotante para aplicaciones financieras, para eso son las clases decimales en lenguajes como Python y C#. Los números de punto flotante son para un cómputo científico eficiente. Pero la eficiencia es inútil sin precisión, ¡así que recuerda la fuente de los errores de redondeo y codifica en consecuencia!

Traducción: Espartaco Palma

Leer contribución original