Haskell 类型转换和相等行为

Haskell 类型转换和相等行为,haskell,floating-point,precision,Haskell,Floating Point,Precision,我是Haskell的新手,刚刚偶然发现了这个问题。我正试图找出一个解释,但我没有足够的经验来确定Haskell类型 职能: mystery :: Int -> Int -> Float -> Bool mystery x y z = not ((x==y) && ((fromIntegral y) == z )) 表现得像看上去的那样。它基本上是检查值是否都不相等,但从整数y进行类型转换,以确保它可以与z进行比较 如果这是真的,那么为什么: case1 = d

我是Haskell的新手,刚刚偶然发现了这个问题。我正试图找出一个解释,但我没有足够的经验来确定Haskell类型

职能:

mystery :: Int -> Int -> Float -> Bool
mystery x y z = not ((x==y) && ((fromIntegral y) == z ))
表现得像看上去的那样。它基本上是检查值是否都不相等,但从
整数
y
进行类型转换,以确保它可以与
z
进行比较

如果这是真的,那么为什么:

case1 = do 
    if mystery 1 1 1.00000001 -- a very small number
        then putStrLn "True"
        else putStrLn "False"
打印错误(即,所有值都相等,因此
1==1==1.00000001
),而:

真的吗?(即,这些值并不都相等)


我知道这可能与精确性有关,但我不明白。非常感谢您的帮助。

您的代码可以简化为:

> (1.00000001 :: Float) == 1
True

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

您的代码可以简化为:

> (1.00000001 :: Float) == 1
True

看起来
Float
没有足够的精度来存储
1.00000001
的最后一位,因此它被截断为普通
1
,浮点运算通常是近似的,并且
=
不是该规则的例外之一。单精度浮点(
Float
)的精度很快就会耗尽,而更常用的双精度浮点(
double
)的精度更高。在这两种情况下,十进制分数将近似转换为二进制浮点,然后相等性测试也将是近似的。一般规则:浮点表示法不是数字,它们甚至不是
Eq
类的合法实例。如果你想使用它们,你需要注意它们的局限性

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


对于您必须考虑的一些细节,请查看经典,不要跳过脚注中的更正和更新。

浮点运算通常是近似的,并且
=
不是该规则的例外。单精度浮点(
Float
)的精度很快就会耗尽,而更常用的双精度浮点(
double
)的精度更高。在这两种情况下,十进制分数将近似转换为二进制浮点,然后相等性测试也将是近似的。一般规则:浮点表示法不是数字,它们甚至不是
Eq
类的合法实例。如果你想使用它们,你需要注意它们的局限性

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


对于您必须考虑的一些细节,请查看经典,不要跳过脚注中的更正和更新。

1/10^n
不能用base2浮点(IEEE 754)表示,因此该值可能被截断

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

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

1/10^n
不能用base2浮点(IEEE 754)表示,因此该值可能被截断

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

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


不是==不准确,它的工作做得很好。它的数值文字作为浮点太不精确了。@augustss,事实上,有一个阈值,一个例子跨越,另一个没有跨越。我想表达的主要观点是,浮点运算很繁琐,并不总是“有意义的”。不是==不准确,而是它完美地完成了它的工作。它的数值文字作为浮点太不精确了。@augustss,事实上,有一个阈值,一个例子跨越,另一个没有跨越。我想表达的主要思想是,浮点很复杂,并不总是“有意义”。如果GHC能像处理范围外积分那样警告您不可表示的浮点文字,那可能会很好。也许您可以在GHC Trac上打开一个票证。您应该对所有涉及浮点数的实际代码使用
Double
,除非您对
Float
@jberryman有非常特殊的需求,否则大多数分数浮点数文字无法准确表示。虽然这个建议有很多优点,但我怀疑它会惹恼太多人,导致太多的混乱。如果GHC能像处理范围外积分那样警告您不可表示的浮点文字,那可能会更好。也许您可以在GHC Trac上打开一个票证。您应该对所有涉及浮点数的实际代码使用
Double
,除非您对
Float
@jberryman有非常特殊的需求,否则大多数分数浮点数文字无法准确表示。虽然这个建议有很多优点,但我怀疑它会惹恼太多的人,导致太多的混乱。虽然
1/10^n
确实不能准确地表示,但这与问题并不真正相关。IEEE 754中的实际表示在很大程度上影响了结果。但是,可表示的值也可能由于精度而被截断。当使用最终参数
1.00000000 7450580596923828125
1.00000011920928955078125
调用
谜团时,您会看到同样的问题,这两个参数都可以用base-2浮点表示。这里的问题是精度,而不是代表性。确切地说,是一个分数值大于另一个fra