Punto flotante

En esta página, aprenderás cómo los equipos almacenan números que no son enteros.

La forma en que las computadoras almacenan números que no son enteros se llama punto flotante.

La notación científica (como 2.350.000 = 2,35 × 106) utiliza potencias de diez para representar valores muy grandes o muy pequeños. El punto flotante (o coma flotante) (floating point) es la misma idea pero con potencias de dos.

¿De dónde viene ese nombre tan gracioso?
Este nombre no obvio se usa porque solía haber un punto fijo notación no entera con unfijo número de dígitos después del decimal punto. Por ejemplo, se utilizó una notación de punto fijo con dos dígitos después del punto decimal para representar una cantidad de dinero en dólares y centavos: $ 82.47. Pero las computadoras de hoy en día siempre usan punto flotante para valores no enteros.

AAP-1.A.4
En Snap!, puedes almacenar cualquier tipo de datos en una variable (número, cadena de texto, lista, disfraz, elemento de prueba, etc.). Pero en algunos idiomas, debes declarar qué tipo de datos almacenarán tus variables. Si tienes una colección de valores, es obvio que necesitarás una lista para almacenarla. Pero no siempre es obvio cuál es la mejor manera de representar un valor en un programa de computadora. Por ejemplo, la forma más sencilla de representar una cantidad de dinero es en punto flotante porque permite decimales. Pero si usas punto flotante para almacenar un valor como 3.20, es probable que se muestre al usuario como 3.2, y las personas rara vez escriben dinero de esta manera. En su lugar, aunque es más esfuerzo de programación, puedes optar por crear un tipo de datos abstracto dinero, dólares: () centavos: () con dos entradas enteras para que pueda controlar cómo se muestra el valor.

DAT-1.B.3

El punto flotante permite a las computadoras almacenar números muy grandes y también decimales, pero el formato todavía tiene un número específico de bits, y eso limita el rango de valores de punto flotante y operaciones matemáticas al igual que con los enteros. Sin embargo, con el punto flotante, los valores que exceden la limitación pueden resultar en redondear errores en su lugar.

  1. Por ejemplo, prueba(1)/(3) una vez con bignums encendidos y una vez con bignums apagado.

La representación decimal de 1/3 es 0.33333... Tiene infinitos dígitos, por lo que lo más cerca que puedes estar en punto flotante no es exactamente ⅓; se corta después de un tiempo porque su computadora no tiene suficiente memoria.

Los errores de redondeo pueden dar lugar a algunos resultados bastante poco intuitivos...

  1. Prueba (0.2) + (0.4) y luego (7.6) + (8.7).

Esto no es un error de Snap!, que reporta correctamente el resultado calculado por el hardware de punto flotante.

¿Cómo pueden estos cálculos simples obtener resultados incorrectos?
Estos resultados parecen sorprendentes porque un valor fraccionario como 0.2 se puede representar exactamente. en decimal (a diferencia del ejemplo de 1/3). Pero en binario, solo las fracciones cuyo denominador es una potencia de 2 pueden ser representadas exactamente. Así que 2/16 se puede representar exactamente, pero 2/10 no puede. La representación binaria de punto flotante de 0.2 es un poco demasiado grande, al igual que la representación binaria de 0.4. La adición de dos valores ligeramente demasiado grandes produce un error lo suficientemente grande como para llegar al siguiente valor representable más alto.

No importa lo bueno que sea el hardware, es probable que ciertos tipos de cálculos den errores graves en el punto flotante. Un ejemplo simple es restar dos números que son casi iguales en valor. La respuesta correcta será cercana a cero, y si está lo suficientemente cerca, lo hará desbordar y se podría reportar un cero exacto.

Los errores de punto flotante pueden ser muy costosos e incluso pueden matar personas.
Brian wants to add links to these references. --MF, 10/16/19

Un ejemplo notorio es el destino del cohete Ariane lanzado el 4 de junio de 1996 (Agencia Espacial Europea 1996). En el 37º segundo de vuelo, el sistema de referencia inercial intentó convertir un número de punto flotante de 64 bits en un número de 16 bits, pero en su lugar desencadenó un error de desbordamiento que fue interpretado por el sistema de guía como datos de vuelo, haciendo que el cohete se desviara de su curso y fuera destruido.

El sistema de defensa antimisiles Patriot utilizado durante la Guerra del Golfo también se volvió ineficaz debido a un error de redondeo (Skeel 1992, U.S. GAO 1992). El sistema utilizaba un registro de tiempo entero que se incrementaba a intervalos de 0,1 s. Sin embargo, los enteros se convirtieron a números decimales multiplicando por la aproximación binaria de 0.1, 0.0001100110011001100110011002 = 209715/2097152.

Como resultado, después de 100 horas (3.6 × 106 ticks), un error de

(\frac{1}{10}-\frac{209715}{2097152})(3600\times100\times10)=\frac{5625}{16384} \approx 0.3433 \text{ segundos}

se había acumulado. Esta discrepancia hizo que el sistema Patriot se reciclara continuamente en lugar de apuntar adecuadamente. Como resultado, un misil Scud iraquí no pudo ser atacado y se le permitió detonar en un cuartel, matando a 28 personas.

De Conversión analógica y digital, por contribuidores de Wikibooks, https://en.wikibooks.org/wiki/Analog_and_Digital_Conversion/Fixed_Wordlength_Effects

La aritmética informática en números enteros es sencilla. O bien se obtiene un resultado entero exactamente correcto o, si el resultado no encaja en la representación entera (no bignum), se obtiene un error de desbordamiento (overflow) y el resultado es, por lo general, convertido a representación de punto flotante (como se hizo con 30!).

Por el contrario, la aritmética informática en números de punto flotante es difícil acertar exactamente. Antes de 1985, cada modelo de computadora tenía un formato de punto flotante ligeramente diferente, y todos ellos obtuvieron respuestas incorrectas a ciertos problemas. Esta situación fue resuelta por el estándar del IEEE para aritmética en punto flotante (IEEE 754), que ahora es utilizado por todos los fabricantes de computadoras y se ha mejorado varias veces desde que se creó en 1985.

Existen alternativas al punto flotante.
Si los errores sutiles en el cálculo de punto flotante resultan ser inaceptables en una aplicación en particular, el software puede usar representaciones alternativas:

Con bignums desactivado, cuando un resultado es demasiado grande para ser un entero, se convierte en punto flotante.
(30) ! reporta 2.6525285981219103e+32

  1. Prueba 200! de nuevo con bignums apagados.
    ((200) !) reporta infinito

Qué ocurre? Aunque 200! es muy grande, no es "infinito". Este reporte se debe a la limitación de tamaño del formato de punto flotante. Si el resultado de un cálculo es mayor que el rango de números que se pueden almacenar, entonces la computadora devuelve un código especial que los lenguajes imprimen como infinito o ∞.

En punto flotante, hay códigos especiales para el infinito, –infinito (más pequeño que cualquier valor finito), y "No es un número", que es la notificación utilizada para cálculos ilegales como 0/0.
(0) / (0) reporta NaN
  1. Imagina undecimal representación de punto flotante con un dígito significativo y un rango de exponentes de 10-2 hasta 102. El número positivo más pequeño representable en esta notación es 0.01(1×10-2) y el más grande es 900 (9×102). Esboce una recta numérica de 0 a 1000 y marque todos los valores positivos representables en esta notación. ¿Qué puede decir sobre el espaciado de los valores? ¿Cuántos valores fraccionarios son representables? ¿Cuántos valores enteros inferiores a 1000 no son representables? ¿Cuáles son las fortalezas y debilidades de esta elección de valores representables? (El punto flotante real tiene muchos más valores representables, por supuesto, pero la forma en que están espaciados en la recta numérica es similar a esto).

¿Cómo sabe un lenguaje de programación si interpretar una secuencia de bits como un entero, un punto flotante, una cadena de texto de caracteres Unicode, una instrucción o algo más? Los lenguajes de programación difieren en cómo lo hacen, pero siempre hay algunos extra secuencia de bits que codifica el tipo de datos de cualquier secuencia de bits que le diga al ordenador cómo interpretarla.

En el nivel más bajo de abstracción de software, todo en un ordenador se representa como una secuencia binaria. Por ejemplo:
Pero los diferentes lenguajes usan tipos de datos de manera diferente.

En lenguajes bien diseñados (aquellos basados en Scheme, por ejemplo), ese código de tipo de datos se adjunta al valor en sí. En otros idiomas, cuando se crea una variable, hay que decir qué tipo de valor contendrá, y el tipo de datos se adjunta a la variable, por lo que no puede obtener respuestas exactas cuando los valores son enteros y también poder manejar valores no enteros de la misma variable. Así que en lugar de ver:
variables de programa (foo)
ves cosas como:
entero (foo)
En un idioma con escritura dinámica (donde no tiene que declarar los tipos de variables) es tan fácil hacer una lista cuyos elementos son de diferentes tipos de datos como lo es hacer una cuyos elementos sean todos del mismo tipo (todos los enteros o todas las cadenas de caracteres, etc.)

Snap! tiene fortalezas que muchos lenguajes de programación no tienen, y es muy probable que tu próxima clase de computación use uno de esos otros idiomas.

  1. DAT-1.B
    Habla con tu compañero¿Cuáles son algunas de las consecuencias de usar un número fijo de bits para representar números?