我尝试使用这段代码计算圆周率到多位小数:
def pi():
pi = 0
for k in range(350):
pi += (4./(8.*k+1.) - 2./(8.*k+4.) - 1./(8.*k+5.) - 1./(8.*k+6.)) / 16.**k
return pi
print(pi())
我为什么会收到一个错误,上面写着OverflowError: (34, 'Result too large')
?
我尝试使用这段代码计算圆周率到多位小数:
def pi():
pi = 0
for k in range(350):
pi += (4./(8.*k+1.) - 2./(8.*k+4.) - 1./(8.*k+5.) - 1./(8.*k+6.)) / 16.**k
return pi
print(pi())
我为什么会收到一个错误,上面写着OverflowError: (34, 'Result too large')
?
Python的浮点数既不是任意精度也不是无限大小。当k = 349时,16.**k
太大了 - 几乎是2^1400。幸运的是,decimal
库允许任意精度并可以处理这样的大小:
import decimal
decimal.getcontext().prec = 100
def pi():
pi = decimal.Decimal(0)
for k in range(350):
pi += (decimal.Decimal(4)/(decimal.Decimal(8)*decimal.Decimal(k+1))...)
您已经达到了平台对float
类型的支持上限,可能是在 k = 256
之后:
>>> k = 256
>>> (4./(8.*k+1.) - 2./(8.*k+4.) - 1./(8.*k+5.) - 1./(8.*k+6.)) / 16.**k
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: (34, 'Result too large')
>>> k = 255
>>> (4./(8.*k+1.) - 2./(8.*k+4.) - 1./(8.*k+5.) - 1./(8.*k+6.)) / 16.**k
3.19870064997e-313
参见 sys.float_info
以查看精度限制,但是无论如何,你不太可能在当前的CPU和操作系统组合中达到100个有效数字; 我的64位OS X的MacBook Pro仅支持15个有效数字。
使用decimal
模块可以超越硬件限制。
from decimal import Decimal, localcontext
def pi():
with localcontext() as ctx:
ctx.prec = 100 # 100 digits precision
pi = Decimal(0)
for k in range(350):
pi += (Decimal(4)/(Decimal(8)*k+1) - Decimal(2)/(Decimal(8)*k+4) - Decimal(1)/(Decimal(8)*k+5) - Decimal(1)/(Decimal(8)*k+6)) / Decimal(16)**k
return pi
16.**256太大了,无法存储在双精度浮点数中。建议您将循环运行更少的次数,比如range(250),因为更大的k值对前100位数字没有贡献。
您可以尝试使用乘以16.*(-k)而不是除以16.*k的方法。对于大的k值,这个数字将被舍入为零,因此不会导致运行时错误。
我建议您使用numpy.power而不是**,它可以更好地处理溢出。例如,在您的代码中,numpy.power(16.,256)将评估为inf,将有限数除以inf得到零,就像上一段中建议的方法一样,避免了运行时错误。
我使用的是Python3.6 AMD64版本,我也遇到了这个问题。原因在于Python内置的float
类型是双精度浮点数,占用64位。在大多数编程任务中,64位足够了,但在一些特殊任务中,如科学计算和大数据计算,64位不够用。
这是使用decimal库解决此问题的Python方案。该代码计算圆周率的一千位数字。
import decimal
def pi( prec = 10 ** 3 ):
decimal.getcontext().prec = prec
b = decimal.Decimal(1)
pi = 0
for k in range(prec):
pi += ( b*4/(8*k+1) - b*2/(8*k+4) - b*1/(8*k+5) - b*1/(8*k+6)) / 16**k
return pi
print(pi())
def pi( prec = 10 ** 4 ):
b = 10 ** prec
pi = 0
for k in range(prec):
pi += ( b*4//(8*k+1) - b*2//(8*k+4) - b*1//(8*k+5) - b*1//(8*k+6)) // 16**k
return pi
print(pi())
如果需要近乎无限的精度,请使用十进制。
在某些罕见情况下,如果您正在执行n ** 2
或类似操作。您可以通过将其转换为n * n
来避免错误,因此根据您解决此问题的方式,这可能是一个可靠的解决方法。您的数字将被称为inf
而不是抛出错误,**
执行幂函数并且它是引发错误的函数。
for k in range(350):
太大了,导致出现了这个问题。 - karthikr