4

我首先定义一个大整数n

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

接下来我查看了s1and的行为s2

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在不损失精度的情况下,最好的计算方法是什么?

4

1 回答 1

15

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

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

最后,您的前两个比较比较Doubles;和n 转换Double,s2 转换Double, 并且s1都是相等的。然而,在第三个比较中,ns2都是Integers;它们可以作为Integers 进行比较,因此调用fromIntegral它们是无操作的,并且它们的未转换整数值是不同的。如果您强制转换为Double,则值将再次相等:

Prelude> ((fromIntegral n) :: Double) == ((fromIntegral s2) :: Double)
True
于 2013-08-14T20:13:26.330 回答