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

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

因为浮点数不准确 (维基百科)

  • 那么你们两个的挑剔者说的是,浮点数只是在不准确时才是不准确的?哇,没有什么能超过你的人.如果您的数学系统中的"1.1*3!= 3.3",则*不准确. (16认同)
  • -1误导,抱歉.IEEE浮点数*非常准确*,您只需要注意带有十进制数的舍入误差.试图表示十进制中的1/3(0.3333 ...)等分数时遇到同样的问题. (8认同)
  • 同意.这个问题不是准确性,而是代表性问题.可以完全表示的数字是完全准确的.那些介于这些数字之间的东西只能近似,而且这就是问题所在. (5认同)
  • @Seth:我没有在学校学到1/3是0.3333333 ... 3其中3s的数量是有限的并且取决于已经设定的精度. (5认同)
  • 当然这是准确的......出现问题的是转换成二进制浮点数.所以它准确,可重复和可预测,有点令人惊讶. (3认同)
  • @ sepp2k:仍然不是一个准确性问题.只是一个表示问题,因为内存是有限的.浮点运算为错误的问题提供了正确的答案:D (3认同)

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)

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

  • 你甚至可以写`let a = 1.1 + 1.1 + 1.1 :: Rational`,不用担心精度的损失(文字`1.1`实际上是`fromRational(11%10)`的缩写. (8认同)

mic*_*tan 6

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

请参阅浮点/舍入错误的简单示例是什么?


Set*_*eth 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
Run Code Online (Sandbox Code Playgroud)

  • 不,1.1不表示为1.1000000000000001.它表示为1.0001100110011001100110011001100110011001100110011010(基数2),当转换为十进制时,舍入为1.100000000000000001 (9认同)

Ign*_*ams 5

很少有浮点数可以使用IEEE 754表示精确表示,因此它们总是有点偏差.