为什么ghci说1.1 + 1.1 + 1.1> 3.3是真的吗?

时间:2010-01-10 21:14:18

标签: haskell floating-accuracy ghci

我最近经历了一个Haskell教程,并在交互式ghci shell中尝试一些简单的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

有人知道那是为什么吗?

7 个答案:

答案 0 :(得分:36)

因为1.13.3floating point numbers。十进制分数(例如.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。

有关该主题的更多信息,请阅读What Every Computer Scientist Should Know About Floating Point Arithmetic

为了在Haskell中更精确地表示有理数,你总是可以使用有理数据类型Ratio;加上bignums(任意大整数,Haskell中的Integer,而不是固定大小的Int)作为分子和分母的类型,你可以表示任意精确的有理数,但速度要慢得多速度比浮点数,它是在硬件中实现的,并针对速度进行了优化。

浮点数是一种优化,用于科学计算和数值计算,它可以在高速下折衷精度,只要你知道舍入及其如何,就可以在很短的时间内执行大量的计算。影响你的计算。

答案 1 :(得分:13)

因为浮点数不准确 (wikipedia)

答案 2 :(得分: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

当然,您为提高准确性而支付了性能损失。

答案 3 :(得分:6)

看起来像是一个典型的浮点错误问题。

请参阅What is a simple example of floating point/rounding error?

答案 4 :(得分:6)

它与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

答案 5 :(得分:5)

很少有浮点数可以使用IEEE 754表示法精确表达,因此它们总是稍微偏离。

答案 6 :(得分:1)

通常,您不应该将浮点数进行比较(出于上述原因)。我能想到的唯一原因是,如果你想说“这个价值有变化吗?”例如,“if(newscore / = oldscore)”然后采取一些行动。只要你没有比较两个单独计算的结果来检查它们是否恰好相等(那么即使它们是数学上,否则它们可能会反过来),这是可以的。