类型转换和相等行为

时间:2015-09-21 19:42:26

标签: haskell floating-point precision

我是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"

打印真实吗? (即,这些值并非全部相等)

我知道它可能与精确度有关,但我不明白。非常感谢任何帮助。

3 个答案:

答案 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)