哈斯克尔大数计算



我正在尝试用大数字进行一些计算

λ: let r  = 291381631919914084
λ: let t = 1165526527679656343
λ: sqrt(4 * r * r - 4 * r + 1 + 8 * t) - 2 * r + 1
1.0

答案应该是8.0000...是否有我应该用于此类计算的包?还是在前奏中我应该做些什么?

正确答案确实非常接近8.0.您遇到了数值精度问题:平方根是使用 IEEE 754("双精度")二进制 64 格式计算的,其 53 位精度不足以在此处给出准确的结果。

更详细地说:sqrt(4 * r * r - 4 * r + 1 + 8 * t)的真正价值是,50个有效数字:

582763263839828175.00000000000000000686385063746811

最接近该数量的可表示 IEEE 754 二进制 64 值为:

582763263839828224.0

。与真实值相差约 49.0。同样,值2*r在转换为浮点时会失去精度。

您可能会想通过提高精度来解决此问题,但正如数值工作中经常发生的那样,在这种情况下,最好重新设计算法以避免(或至少改善)数值问题。您正在计算的值的形式为sqrt(a * a + b) - a(带a = 2 * r - 1b = 8 * t)。该数量可以改写为b / (sqrt(a * a + b) + a)形式,并且(假设ab都是正数),后一个表达式将给出更准确的结果。

下面是两个表达式给出相同结果的快速演示。

Prelude> let a = 43
Prelude> let b = 7
Prelude> sqrt(a * a + b) - a
8.131845707602992e-2
Prelude> b / (sqrt(a * a + b) + a)
8.131845707603225e-2

我们使用较小的ab值,因此数字问题还不错,但请注意,最后 4 位数字仍然存在差异。(这里的确切值是0.081318457076032250005683932322636450,到 35 个有效数字。

并将这种形式的表达式与您的值一起使用:

Prelude> let r = 291381631919914084
Prelude> let t = 1165526527679656343
Prelude> let a = 2*r - 1; b = 8*t in b / (sqrt(a*a+b) + a)
8.0

正如其他回答者所指出的,答案并不完全8.0,但8.0是最接近真实答案的IEEE 754二进制64浮点值。

>我相信8也不是一个正确的答案;你给出的数字不是平方的:

Math.NumberTheory.Powers.Squares> r  = 291381631919914084
Math.NumberTheory.Powers.Squares> t = 1165526527679656343
Math.NumberTheory.Powers.Squares> isSquare (4*r*r - 4*r + 1 + 8*t)
False

但是,如果它是您想要的答案,您可以得到以下答案:

Math.NumberTheory.Powers.Squares> integerSquareRoot (4*r*r - 4*r + 1 + 8*t) - 2*r + 1
8

算术包提供了这些函数。

或者,您可以根据需要获得确切答案的任意位数:

Data.Number.CReal> sqrt (4*r*r - 4*r + 1 + 8*t) - 2*r + 1 :: CReal
8.0000000000000000068638506374681082902485

数字包提供此类型。

我把这些数字和公式放在Rstudio中,也得到了1。你确定答案是8吗?也许添加更多括号以确保您的操作顺序正确。

最新更新