我是Haskell的新手,只是偶然发现了这个问题。我试图找出解释,但我没有足够的Haskell类型经验确定。
功能:
mystery :: Int -> Int -> Float -> Bool
mystery x y z = not ((x==y) && ((fromIntegral y) == z ))
表现得像它一样。它基本上检查值是否都不相等,但是从Integral
y
进行类型转换以确保它可以与z
进行比较
如果这是真的,那么为什么:
case1 = do
if mystery 1 1 1.00000001 -- a very small number
then putStrLn "True"
else putStrLn "False"
打印错误(即。值全部相等,所以1 == 1 == 1.00000001
)而:
case2 = do
if mystery 1 1 1.0000001 -- a larger number
then putStrLn "True"
else putStrLn "False"
打印真实吗? (即,这些值并非全部相等)
我知道它可能与精确度有关,但我不明白。非常感谢任何帮助。
答案 0 :(得分:7)
浮点运算通常是近似值,==
不是该规则的例外情况之一。单精度浮点(Float
)很快就会耗尽精度,而通常更有用的双精度浮点(Double
)会有更多。在任何一种情况下,您的小数部分将近似转换为二进制浮点,然后相等性测试也将是近似值。一般规则:浮点表示不是数字,它们甚至不是Eq
类的合法实例。如果你想使用它们,你需要注意它们的局限性。
在这种情况下,您需要考虑何时要考虑等于浮点表示的整数。您可能想要也可能不想直接依赖内置的比较和舍入操作。
有关您需要考虑的一些细节,请查看经典What Every Computer Scientist Should Know About Floating-Point Arithmetic,不要跳过脚注中的更正和更新。
答案 1 :(得分:5)
您的代码可以简化为:
> (1.00000001 :: Float) == 1
True
看起来Float
根本没有足够的精确度来存储1.00000001
的最后几位,因此它会被截断为普通1
。
答案 2 :(得分:3)
1/10^n
无法在base2浮点(IEEE 754)中表示,因此该值可能会被截断。
从语义上讲,对于整数比较,它可能比truncate
浮点值更准确。
mystery :: Int -> Int -> Float -> Bool
mystery x y z = not (x == y && y == truncate z)