parse fromintegral frominteger float convertir haskell floating-accuracy ghci

haskell - fromintegral - ¿Por qué ghci dice que 1.1+1.1+1.1> 3.3 es verdadero?



fromintegral haskell (7)

Pocos flotadores se pueden expresar exactamente utilizando la representación IEEE 754, por lo que siempre estarán un poco desconectados.

He estado revisando un tutorial de Haskell recientemente y noté este comportamiento cuando probaba algunas expresiones simples de Haskell en el shell ghci interactivo:

Prelude> 1.1 + 1.1 == 2.2 True Prelude> 1.1 + 1.1 + 1.1 == 3.3 False Prelude> 1.1 + 1.1 + 1.1 > 3.3 True Prelude> 1.1 + 1.1 + 1.1 3.3000000000000003

¿Alguien sabe por qué es eso?


Porque los números de coma flotante no son precisos (wikipedia)


Puede evitar los errores de punto flotante en Haskell usando tipos racionales:

Prelude Data.Ratio> let a = (11 % 10) + (11 % 10) + (11 % 10) Prelude Data.Ratio> a > (33 % 10) False Prelude Data.Ratio> fromRational a 3.3

Por supuesto, paga una penalización de rendimiento por la mayor precisión.


Tiene que ver con la forma en que funcionan los números flotantes de IEEE.

1.1 se representa como 1.1000000000000001 en coma flotante, 3.3 se representa como 3.2999999999999998.

Entonces 1.1 + 1.1 + 1.1 es en realidad

1.1000000000000001 + 1.1000000000000001 + 1.1000000000000001 = 3.3000000000000003

Cuál, como puedes ver es realmente más grande que 3.2999999999999998.

La solución habitual es no evaluar la igualdad o verificar si un número está dentro del objetivo +/- un pequeño epsilon (que define la precisión que necesita).

Ej .: si ambos son verdaderos, entonces la suma es "igual" a 3.3 (dentro del error permitido).

1.1 + 1.1 + 1.1 < 3.3 + 1e9 1.1 + 1.1 + 1.1 > 3.3 - 1e9


En general, no debería comparar carrozas por igualdad (por los motivos descritos anteriormente). La única razón por la que puedo pensar es si quieres decir "¿ha cambiado este valor?" Por ejemplo, "if (newscore / = oldscore)" luego tome alguna medida. Eso está bien, siempre y cuando no compares el resultado de dos cálculos separados para comprobar si son iguales (porque incluso matemáticamente si lo son, podrían redondear de otro modo).


Porque 1.1 y 3.3 son números de coma flotante . Las fracciones decimales, como .1 o .3, no son exactamente representables en un número de punto flotante binario. .1 significa 1/10. Para representar eso en binario, donde cada dígito fraccionario representa 1/2 n (1/2, 1/4, 1/8, etc.), necesitaría un número infinito de dígitos, 0.000110011 ... repitiéndose infinitamente.

Este es exactamente el mismo problema que representar, digamos, 1/3 en la base 10. En la base 10, necesitarías un número infinito de dígitos, .33333 ... para siempre, para representar exactamente 1/3. Así que trabajando en la base 10, usualmente redondeas, a algo así como .33. Pero si suma tres copias de eso, obtiene .99, no 1.

Para obtener mucha más información sobre el tema, lea Lo que todo científico informático debe saber sobre la aritmética de punto flotante .

Para representar números racionales con mayor precisión en Haskell, siempre puede usar el tipo de datos racional Ratio ; junto con bignums (enteros arbitrariamente grandes, Integer en Haskell, en oposición a Int que son de tamaño fijo) como el tipo de numerador y denominador, puede representar números racionales arbitrariamente precisos, pero a una velocidad significativamente más lenta que los números de coma flotante, que son implementado en hardware y optimizado para la velocidad.

Los números de coma flotante son una optimización, para cálculo científico y numérico, que intercambia precisión para alta velocidad, lo que le permite realizar una gran cantidad de cálculos en poco tiempo, siempre que sepa redondear y cómo afecta sus cálculos. .