为什么地板失去精确度,它如何影响平等的传递性?

时间:2013-08-14 19:31:45

标签: haskell equality ghci floor transitivity

我首先定义一个大整数n

Prelude> let n = 5705979550618670446308578858542675373983
Prelude> n :: Integer
5705979550618670446308578858542675373983

接下来,我查看了s1s2的行为:

Prelude> let s1 = (sqrt (fromIntegral n))^2
Prelude> let s2 = (floor(sqrt(fromIntegral n)))^2

Prelude> s1 == fromIntegral n
True
Prelude> s1 == fromIntegral s2
True
Prelude> (fromIntegral n) == (fromIntegral s2)
False

由于可能会丢弃任何小数部分,因此不期望最后2个表达式上的相等性。但是,我不认为平等是不及物的(例如n == s1, s1 == s2,但是n != s2。)

此外,floor似乎在整数部分失去精确度,尽管保留了40位有效数字。

Prelude> s1
5.70597955061867e39

Prelude> s2
5705979550618669899723442048678773129216

测试减法时,这种丢失的精度变得明显:

Prelude> (fromIntegral n) - s1
0.0

Prelude> (fromIntegral n) - (fromIntegral s2)
546585136809863902244767

为什么floor会失去精确度,这又如何违反平等的传递性(如果有的话)?

在不损失精度的情况下计算floor . sqrt的最佳方法是什么?

1 个答案:

答案 0 :(得分:14)

不是floor失去精度,而是从Integer(任意精度整数)到Double的转换(浮点值,精度有限) 。因此,fromIntegral n :: Double不再与n相同。

Double有一个53位的尾数(52显式存储,前导隐含),大约相当于16位十进制数。因此,只有结果的(大约)16个最高有效位有效。其余的只是噪音。

最后,您的前两个比较比较Double s;并n 转换Doubles2 已转换Doubles1等于。但是,在第三次比较中,ns2都是Integer s;它们可以比较为Integer s,因此对它们调用fromIntegral是无操作,并且它们的非转换整数值是不同的。如果您强制转换为Double,则值会再次变为相等:

Prelude> ((fromIntegral n) :: Double) == ((fromIntegral s2) :: Double)
True