Haskell 精度损失';sqrt&x27;哈斯克尔

Haskell 精度损失';sqrt&x27;哈斯克尔,haskell,Haskell,在ghci终端中,我使用sqrt函数与Haskell一起计算一些方程 我注意到,当我的sqrt结果被简化时,我有时会失去精度 比如说, sqrt 4 * sqrt 4 = 4 -- This works well! sqrt 2 * sqrt 2 = 2.0000000000000004 -- Not the exact result. 通常情况下,我希望得到2的结果 有没有办法得到正确的简化结果? 在Haskell中如何工作?您不会失去精度。你的精确度有限 2的平方根是实数,但不是有理数,因

在ghci终端中,我使用
sqrt
函数与Haskell一起计算一些方程

我注意到,当我的
sqrt
结果被简化时,我有时会失去精度

比如说,

sqrt 4 * sqrt 4 = 4 -- This works well!
sqrt 2 * sqrt 2 = 2.0000000000000004 -- Not the exact result.
通常情况下,我希望得到
2
的结果

有没有办法得到正确的简化结果?

在Haskell中如何工作?

您不会失去精度。你的精确度有限


2的平方根是实数,但不是有理数,因此它的值不能由任何计算机精确表示(当然,符号表示除外)


即使您定义了一个非常大的精度类型,它也无法精确表示2的平方根。您可能会获得更高的精度,但永远不足以精确地表示该值(除非您有一台内存无限的计算机,在这种情况下,请雇用我)。

您不会失去精度。你的精确度有限


2的平方根是实数,但不是有理数,因此它的值不能由任何计算机精确表示(当然,符号表示除外)


即使您定义了一个非常大的精度类型,它也无法精确表示2的平方根。你可能会得到更高的精度,但永远不足以精确地表示该值(除非你有一台内存无限的计算机,在这种情况下,请雇佣我)。

Haskell中有可用的精确数字库。想到的两个是和包中的
CReal
模块。(
cyclomicnumbers
numbers不支持您可能喜欢的对复数的所有操作,但整数和有理数的平方根在域中。)


Haskell中有可用的精确数字库。想到的两个是和包中的
CReal
模块。(
cyclomicnumbers
numbers不支持您可能喜欢的对复数的所有操作,但整数和有理数的平方根在域中。)


对这些结果的解释在于
sqrt
函数返回的值的类型:

> :t sqrt
sqrt :: Floating a => a -> a
浮动a
表示返回的值属于浮动类型类。 属于此类的所有类型的值都存储为浮点数。为了覆盖更大范围的数字,这些方法牺牲了精度

双精度浮点数可以覆盖非常大的范围,但精度有限,无法对所有可能的数字进行编码。2的平方根(√2) 其中一个是:

> sqrt 2
1.4142135623730951
> sqrt 2 + 0.000000000000000001
1.4142135623730951
如上所述,双精度浮点数不可能精确到足以表示√2+0.000000000000000001,它只是四舍五入到最接近的近似值,可以使用浮点编码表示

正如另一张海报所提到的,√2是一个无理数,可以简化为需要无限位数才能正确表示。因此,不能用浮点数忠实地表示它。这会导致错误,比如在将其与自身相乘时注意到的错误

您可以在他们的维基百科页面上了解浮点

我特别建议您阅读另一个堆栈溢出问题的答案:并遵循上面提到的链接,它将帮助您了解引擎盖下发生了什么


注意,这在每种语言中都是一个问题,不仅仅是Haskell。一种完全消除它的方法是使用符号计算库,但它们比CPU提供的浮点数字慢得多。对于许多计算而言,浮点导致的精度损失不是问题。

对这些结果的解释在于
sqrt
函数返回的值的类型:

> :t sqrt
sqrt :: Floating a => a -> a
浮动a
表示返回的值属于浮动类型类。 属于此类的所有类型的值都存储为浮点数。为了覆盖更大范围的数字,这些方法牺牲了精度

双精度浮点数可以覆盖非常大的范围,但精度有限,无法对所有可能的数字进行编码。2的平方根(√2) 其中一个是:

> sqrt 2
1.4142135623730951
> sqrt 2 + 0.000000000000000001
1.4142135623730951
如上所述,双精度浮点数不可能精确到足以表示√2+0.000000000000000001,它只是四舍五入到最接近的近似值,可以使用浮点编码表示

正如另一张海报所提到的,√2是一个无理数,可以简化为需要无限位数才能正确表示。因此,不能用浮点数忠实地表示它。这会导致错误,比如在将其与自身相乘时注意到的错误

您可以在他们的维基百科页面上了解浮点

我特别建议您阅读另一个堆栈溢出问题的答案:并遵循上面提到的链接,它将帮助您了解引擎盖下发生了什么


注意,这在每种语言中都是一个问题,不仅仅是Haskell。一种完全消除它的方法是使用符号计算库,但它们比CPU提供的浮点数字慢得多。对于许多计算来说,浮点运算造成的精度损失不是问题。

对于您正在寻找的问题有一些很好的答案,每个程序员/计算机科学家都应该了解浮点运算:我认为这是一个不错的问题。任何否决它的人可能都没有彻底阅读。如果你真的想,你可以用重写规则做一点,但你可能得不到一致的结果。事实上,我们已经和GHC谈了很多,这就是为什么实施一些优化如此困难的原因。T