使用使用Gauss-Legendre算法计算pi的python脚本时出现此错误。在获得此项之前,您最多只能使用1024次迭代:
C:\Users\myUsernameHere>python Desktop/piWriter.py
End iteration: 1025
Traceback (most recent call last):
File "Desktop/piWriter.py", line 15, in <module>
vars()['t' + str(sub)] = vars()['t' + str(i)] - vars()['p' + str(i)] * math.
pow((vars()['a' + str(i)] - vars()['a' + str(sub)]), 2)
OverflowError: long int too large to convert to float
这是我的代码:
import math
a0 = 1
b0 = 1/math.sqrt(2)
t0 = .25
p0 = 1
finalIter = input('End iteration: ')
finalIter = int(finalIter)
for i in range(0, finalIter):
sub = i + 1
vars()['a' + str(sub)] = (vars()['a' + str(i)] + vars()['b' + str(i)])/ 2
vars()['b' + str(sub)] = math.sqrt((vars()['a' + str(i)] * vars()['b' + str(i)]))
vars()['t' + str(sub)] = vars()['t' + str(i)] - vars()['p' + str(i)] * math.pow((vars()['a' + str(i)] - vars()['a' + str(sub)]), 2)
vars()['p' + str(sub)] = 2 * vars()['p' + str(i)]
n = i
pi = math.pow((vars()['a' + str(n)] + vars()['b' + str(n)]), 2) / (4 * vars()['t' + str(n)])
print(pi)
理想情况下,我希望能够插入一个非常大的数字作为迭代值,稍后再回来查看结果。
任何帮助表示赞赏! 谢谢!
答案 0 :(得分:4)
浮点数只能表示最多为sys.float_info.max或1.7976931348623157e + 308的数字。一旦你有一个超过308位数的int(或左右),你就会陷入困境。当p1024有309个数字时,您的迭代失败:
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216L
你必须为pi找到一个不同的算法,一个不需要这么大值的算法。
实际上,你必须小心周围的花车,因为它们只是近似值。如果您修改程序以打印pi的连续近似值,它看起来像这样:
2.914213562373094923430016933707520365715026855468750000000000
3.140579250522168575088244324433617293834686279296875000000000
3.141592646213542838751209274050779640674591064453125000000000
3.141592653589794004176383168669417500495910644531250000000000
3.141592653589794004176383168669417500495910644531250000000000
3.141592653589794004176383168669417500495910644531250000000000
3.141592653589794004176383168669417500495910644531250000000000
换句话说,经过4次迭代后,你的近似值已经停止好转。这是由于您使用的浮点数不准确,可能从1/math.sqrt(2)
开始。计算pi的许多数字需要非常仔细地理解数字表示。
答案 1 :(得分:1)
如前面的回答所述,float
类型的数字大小有一个上限。在典型的实现中,sys.float_info.max
是1.7976931348623157e + 308,它反映了对64位浮点数中的指数字段使用10位加号。 (注意1024 * math.log(2)/math.log(10)约为308.2547155599。)
您可以使用Decimal number type向指数大小添加另外六十年。这是一个例子(从ipython解释器会话中剪断):
In [48]: import decimal, math
In [49]: g=decimal.Decimal('1e12345')
In [50]: g.sqrt()
Out[50]: Decimal('3.162277660168379331998893544E+6172')
In [51]: math.sqrt(g)
Out[51]: inf
这表明十进制sqrt()
函数的正确数字大于math.sqrt()
。
答案 2 :(得分:0)
如上所述,获取大量数字会很棘手,但看着所有vars
会伤到我的眼睛。所以这是你的代码的一个版本(1)替换你使用vars
和字典,(2)使用**
而不是数学函数:
a, b, t, p = {}, {}, {}, {}
a[0] = 1
b[0] = 2**-0.5
t[0] = 0.25
p[0] = 1
finalIter = 4
for i in range(finalIter):
sub = i + 1
a[sub] = (a[i] + b[i]) / 2
b[sub] = (a[i] * b[i])**0.5
t[sub] = t[i] - p[i] * (a[i] - a[sub])**2
p[sub] = 2 * p[i]
n = i
pi_approx = (a[n] + b[n])**2 / (4 * t[n])
我没有使用vars
玩游戏,而是使用dictionaries来存储值(这是官方Python教程的链接),这使您的代码更具可读性。你现在甚至可以看到一两个优化。
如评论中所述,您实际上不需要存储所有值,只需存储最后一个值,但我认为在不动态创建变量的情况下查看如何执行操作更为重要。您也可以简单地将值附加到dict
,而不是list
,但是列表始终为零索引,您不能轻易地“跳过”并在任意索引处设置值。在使用算法时,这有时会让人感到困惑,所以让我们开始吧。
无论如何,以上给了我
>>> print(pi_approx)
3.141592653589794
>>> print(pi_approx-math.pi)
8.881784197001252e-16
答案 3 :(得分:0)
一个简单的解决方案是安装和使用现在支持Python 3的任意精度mpmath
模块。但是,由于我完全同意DSM您使用vars()
动态创建变量实现算法是一种不受欢迎的方法,我的答案基于代码的his rewrite,并且[通过]修改它以利用mpmath
进行计算。
如果你坚持使用vars()
,你可能会做类似的事情 - 虽然我怀疑这可能会更困难,结果肯定更难以阅读,理解和修改。
from mpmath import mpf # arbitrary-precision float type
a, b, t, p = {}, {}, {}, {}
a[0] = mpf(1)
b[0] = mpf(2**-0.5)
t[0] = mpf(0.25)
p[0] = mpf(1)
finalIter = 10000
for i in range(finalIter):
sub = i + 1
a[sub] = (a[i] + b[i]) / 2
b[sub] = (a[i] * b[i])**0.5
t[sub] = t[i] - p[i] * (a[i] - a[sub])**2
p[sub] = 2 * p[i]
n = i
pi_approx = (a[n] + b[n])**2 / (4 * t[n])
print(pi_approx) # 3.14159265358979