为什么我在进行浮点指数运算时会出现“OverflowError:(34,‘结果太大’)”或“OverflowError:(34,‘数值结果超出范围’)”?
- 2025-02-18 09:23:00
- admin 原创
- 150
问题描述:
我尝试使用此代码将圆周率计算到小数点后几位:
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')
?
解决方案 1:
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))...)
解决方案 2:
您已达到平台支持的限制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 和 OS 组合,它会给您 100 位有效数字;我的 MacBook Pro 搭载 64 位 OS X,仅支持 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
解决方案 3:
16.**256 太大,无法存储在双精度浮点数中。我建议您运行较小的循环,例如 range(250),因为无论如何,较大的 k 值不会对前 100 位数字产生影响。
您还可以尝试乘以 16. (-k),而不是除以 16. k。对于较大的 k,此数字将四舍五入为零,因此不会给您带来运行时错误。
我建议您使用 numpy.power 而不是 **,它可以更好地处理溢出。例如,在您的代码中,numpy.power(16.,256) 的计算结果为 inf,而将有限数除以 inf 会得出零,这可以避免运行时错误,就像上一段中建议的方法一样。
解决方案 4:
我使用python3.6 AMD64,我也遇到了这个问题,这是因为python内置float
是双精度浮点数,它是64位的,在大多数编程任务中,64位已经足够了,但在一些额外的任务中,它是不够的(比如科学计算,大数据计算)
解决方案 5:
这是使用十进制库对此问题的 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())
通过启动此代码,您可以向朋友吹嘘您已经将一万数成了圆周率:)。
解决方案 6:
如果需要几乎无限的精度,请使用十进制。
在某些罕见情况下,如果您正在执行n ** 2
或类似操作。您可以通过将其转换为来避免错误而不捕获它,n * n
因此,根据您如何解决此问题,这可能是一个可靠的解决方案。您的数字将被调用inf
而不是抛出错误,**
幂函数执行并且它是抛出错误的人。
扫码咨询,免费领取项目管理大礼包!