Fre*_*abe 8 haskell floating-accuracy ghci
我最近经历了一个Haskell教程,并在交互式ghcishell中尝试一些简单的Haskell表达式时注意到了这种行为:
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
Run Code Online (Sandbox Code Playgroud)
有谁知道那是为什么?
Bri*_*ell 36
因为1.1并且3.3是浮点数.十进制分数(例如.1或.3)在二进制浮点数中不能精确表示..1表示1/10.要用二进制表示,每个小数位代表1/2 n(1/2,1/4,1/8等),你需要无限数量的数字,0.000110011 ......无限重复.
这与在基数10中表示1/3的问题完全相同.在基数10中,您将需要无限数量的数字,.33333 ......永远,以准确地表示1/3.所以在10号基地工作,你通常会变成类似.33的东西.但如果你加上三个副本,你得到.99,而不是1.
有关该主题的更多信息,请阅读每个计算机科学家应该知道的关于浮点运算的内容.
为了在Haskell中更准确地表示有理数,你总是可以使用有理数据类型Ratio; 加上bignums(任意大整数,Integer在Haskell中,而不是Int固定大小)作为分子和分母的类型,你可以表示任意精确的有理数,但速度明显慢于浮点数,这是在硬件和速度优化.
浮点数是一种优化,用于科学和数值计算,可以高速折衷精度,只要您知道舍入及其如何影响计算,就可以在很短的时间内执行大量计算. .
Yup*_*ing 13
因为浮点数不准确 (维基百科)
daf*_*daf 13
您可以使用有理类型避免Haskell中的浮点错误:
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
Run Code Online (Sandbox Code Playgroud)
当然,您为提高准确性而支付性能损失.
它与IEEE浮点数的工作方式有关.
1.1在浮点表示为1.1000000000000001,3.3表示为3.2999999999999998.
实际上1.1 + 1.1 + 1.1
1.1000000000000001 + 1.1000000000000001 + 1.1000000000000001 = 3.3000000000000003
其中,你可以看到实际上大于3.2999999999999998.
通常的解决方法是要么不评估相等性,要么检查一个数字是否在目标范围内+/-一个小epsilon(它定义了你需要的准确度).
例如:如果两者都为真,那么总和"等于"3.3(在允许的误差范围内).
1.1 + 1.1 + 1.1 < 3.3 + 1e9
1.1 + 1.1 + 1.1 > 3.3 - 1e9
Run Code Online (Sandbox Code Playgroud)