Haskell大数计算

时间:2017-07-14 17:35:26

标签: haskell math

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

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

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

3 个答案:

答案 0 :(得分:10)

正确答案确实非常接近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) - aa = 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浮点值到真正的答案。

答案 1 :(得分:7)

我相信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

arithmoi包提供了这些功能。

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

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

numbers包提供此类型。

答案 2 :(得分:-3)

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