类型转换和相等行为

Type conversion and equality behaviour

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

打印 False(即值都相等,所以 1 == 1 == 1.00000001)而:

case2 = do 
    if mystery 1 1 1.0000001 -- a larger number
        then putStrLn "True"
        else putStrLn "False"

打印为真? (即值不都相等)

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

您的代码可以简化为:

> (1.00000001 :: Float) == 1
True

看起来 Float 根本没有足够的精度来存储 1.00000001 的最后一位,因此它被截断为普通 1.

浮点运算通常是近似的,== 也不例外。单精度浮点数 (Float) 很快就会用完精度,而更常用的双精度浮点数 (Double) 精度会更高。在任何一种情况下,你的小数都会被近似地转换为二进制浮点数,然后相等测试也将是近似的。一般规则:浮点表示不是数字,它们甚至不是 Eq class 的合法实例。如果要使用它们,需要注意它们的局限性。

在这种情况下,您需要考虑何时要考虑整数等于浮点数表示。您可能想也可能不想直接依赖内置的比较和舍入操作。

对于您必须考虑的一些细节,请查看 classic What Every Computer Scientist Should Know About Floating-Point Arithmetic,不要跳过脚注中的更正和更新。

1/10^n 无法以 base2 浮点数 (IEEE 754) 表示,因此该值可能被截断。

从语义上讲,对于整数比较,truncate 浮点值可能更准确。

mystery :: Int -> Int -> Float -> Bool
mystery x y z = not (x == y && y == truncate z)