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

Rob*_*Rob 4 haskell equality transitivity floor ghci

我首先定义一个大整数n:

Prelude> let n = 5705979550618670446308578858542675373983
Prelude> n :: Integer
5705979550618670446308578858542675373983
Run Code Online (Sandbox Code Playgroud)

接下来,我看着的行为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
Run Code Online (Sandbox Code Playgroud)

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

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

Prelude> s1
5.70597955061867e39

Prelude> s2
5705979550618669899723442048678773129216
Run Code Online (Sandbox Code Playgroud)

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

Prelude> (fromIntegral n) - s1
0.0

Prelude> (fromIntegral n) - (fromIntegral s2)
546585136809863902244767
Run Code Online (Sandbox Code Playgroud)

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

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

chi*_*rlu 15

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

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

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

Prelude> ((fromIntegral n) :: Double) == ((fromIntegral s2) :: Double)
True
Run Code Online (Sandbox Code Playgroud)