Rob*_*Rob 4 haskell equality transitivity floor ghci
我首先定义一个大整数n:
Prelude> let n = 5705979550618670446308578858542675373983
Prelude> n :: Integer
5705979550618670446308578858542675373983
Run Code Online (Sandbox Code Playgroud)
接下来,我看着的行为s1和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
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)