首页 > 解决方案 > 如何防止多个小数相乘的“溢出”?

问题描述

我有一个包含 x 非常小的数字的列表,并且想要创建它们的产品。我只想使用纯 Python 或/和 numpy。

      # List A with x very small numbers 
      A =[1.20223398e-072 1.53678559e-067 6.04813112e-041 3.26046833e-104
      3.09114525e-048 7.65394632e-118 4.58886892e-209 7.02220200e-044
      3.40963578e-085 2.79721084e-060 6.99320974e-052 7.65701921e-039
      3.05321642e-103 2.33360119e-050 2.92905105e-044 5.13970623e-044
      6.46863409e-180 1.78254565e-177 6.26061488e-068 5.86281346e-043]

      #creating the product of all elements in A
      np.prod(A)

输出:

0.0

这是一个问题,也许是溢出?!我尝试了什么?

  1. 我试图在一个循环中执行此操作 => 运行时间非常糟糕并且没有工作

输入:

prod = 1
for i in A):
    prod = prod * A

输出:

0.0

  1. 我试图按数量排序,然后从数组中乘以总是第一个和最后一个,然后是第二个和倒数第二个,倒数第三个和第三个,.... => 没有工作以太输入:
prod = 1
A.sort()
for i in range(len(A)):
    prod = prod * (A[i]*A[-i-1])

输出:

0.0

有谁知道如何解决这个问题?

最好的问候克里斯蒂安

标签: python-3.x

解决方案


底层的浮点存储不足以容纳如此小的数字,尤其是它们的乘积,乘法越多,乘积越小。

>>> A[0]*A[1]               
1.8475758562723483e-139
>>> A[0]*A[1]*A[2]          
1.1174381032881437e-179
>>> A[0]*A[1]*A[2]*A[3]     
3.6433715465062613e-283
>>> A[0]*A[1]*A[2]*A[3]*A[4]
0.0

但是,使用这些特定数字,该产品实际上适合一种np.float128类型:

>>> np.prod(A, dtype=np.float128)
6.439950307032109978e-1637

当然,这只是移动了目标:乘以其他数字可能会再次给你一个零。

另一种方法是在 Python 中使用该decimal模块,这将使您在处理精确数字方面具有最大的灵活性。虽然它比 IEEE 浮点数慢得多,但应该可以工作:

>>> import decimal
>>> B = [decimal.Decimal(x) for x in A]
>>> B[0]*B[1]
Decimal('1.847575856272348173712320037E-139')
>>> B[0]*B[1]*B[2]
Decimal('1.117438103288143607857271302E-179')
>>> B[0]*B[1]*B[2]*B[3]
Decimal('3.643371546506261078793026112E-283')
>>> B[0]*B[1]*B[2]*B[3]*B[4]
Decimal('1.126219064996798351280705310E-330')

推荐阅读