【问题标题】:OverflowError: long int too large to convert to float in python溢出错误:long int 太大而无法在 python 中转换为浮点数
【发布时间】:2013-04-23 16:20:50
【问题描述】:

我尝试在 python 中计算泊松分布如下:

p = math.pow(3,idx)
depart = math.exp(-3) * p 
depart = depart / math.factorial(idx)

idx 范围为 0

但我得到了OverflowError: long int too large to convert to float

我尝试将离开转换为float,但没有结果。

【问题讨论】:

  • 阶乘变得真的大,真的
  • 遇到此错误时 idx 的值是多少?
  • 当你想计算阶乘时,用对数代替

标签: python overflow factorial


【解决方案1】:

因子变大真的很快

>>> math.factorial(170)
7257415615307998967396728211129263114716991681296451376543577798900561843401706157852350749242617459511490991237838520776666022565442753025328900773207510902400430280058295603966612599658257104398558294257568966313439612262571094946806711205568880457193340212661452800000000000000000000000000000000000000000L

注意L; 170 的阶乘仍然可以转换为浮点数:

>>> float(math.factorial(170))
7.257415615307999e+306

但是下一个阶乘太大了:

>>> float(math.factorial(171))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: long int too large to convert to float

可以使用decimal module;计算会更慢,但Decimal() 类可以处理这种大小的阶乘:

>>> from decimal import Decimal
>>> Decimal(math.factorial(171))
Decimal('1241018070217667823424840524103103992616605577501693185388951803611996075221691752992751978120487585576464959501670387052809889858690710767331242032218484364310473577889968548278290754541561964852153468318044293239598173696899657235903947616152278558180061176365108428800000000000000000000000000000000000000000')

您必须始终使用 Decimal() 值:

from decimal import *

with localcontext() as ctx:
    ctx.prec = 32  # desired precision
    p = ctx.power(3, idx)
    depart = ctx.exp(-3) * p 
    depart /= math.factorial(idx)

【讨论】:

  • Python中的大数类叫什么?因为170! 远高于 64 位整数的限制。我认为类型是强制的?如果是这样,为什么L 仍然附加到末尾?
  • @HunterMcMillen:Python 长整数仅受操作系统内存分配的限制。 L 表示我们超出了平台的最大 C 整数大小(在我的情况下为 64 位)以显示正在使用长整数;过渡是自动的。见docs.python.org/2/library/…
  • 啊,我明白了。大多数其他语言都有BigInteger 或类似的东西。谢谢。
【解决方案2】:

idx 变大时,math.pow 和/或math.factorial 将变得异常大并且无法转换为浮点值(idx=1000 在我的 64 位机器上触发错误)。您不希望使用 math.pow 函数,因为它比内置的 ** 运算符更早溢出,因为它试图通过更早的浮点转换来保持更高的精度。此外,您可以将每个函数调用包装在 Decimal 对象中以获得更高的精度。

在处理非常大的数字时,另一种方法是使用对数刻度。取每个值的对数(或计算每个值的对数版本)并在对结果取幂之前执行所有必需的操作。这允许您的值暂时离开浮动域空间,同时仍能准确计算位于浮动域内的最终答案。

3 ** idx  =>  math.log(3) * idx
math.exp(-3) * p  =>  -3 + math.log(p)
math.factorial(idx)  =>  sum(math.log(ii) for ii in range(1, idx + 1))
...
math.exp(result)

这将保留在日志域中直到最后,因此您的数字可以变得非常非常大,然后您就会遇到溢出问题。

【讨论】:

  • 我认为3 ** idx =&gt; math.log(3) * math.log(idx) 应该是3 ** idx =&gt; math.log(3) * idx
【解决方案3】:

尝试使用十进制库。它声称支持任意精度。
from decimal import Decimal

另外,您不需要使用math.powpow 是内置的。

【讨论】:

  • 大家好,我尝试使用小数或 scipy,但我得到 ImportError: No module named scipy.stats the same error for decimal
  • 你运行的是什么版本? decimal 库应该是所有人的标准。也许您已将其删除。重新安装python,它会修复它。至于 scipy,它是一个第三方包,所以你必须从 scipy.org 下载它
  • 我将像这样使用泊松:离开 = 离开 + Poisson(3) 以便泊松选择到达间隔时间。但它不起作用。
【解决方案4】:

scipy 模块可以帮助您。

scipy.misc.factorial是阶乘函数,可以使用gamma函数逼近计算阶乘,并使用浮点返回结果。

import numpy
from scipy.misc import factorial

i = numpy.arange(10)
print(numpy.exp(-3) * 3**i / factorial(i))

给予:

[ 0.04978707  0.14936121  0.22404181  0.22404181  0.16803136  0.10081881
  0.05040941  0.02160403  0.00810151  0.0027005 ]

还有一个module to calculate Poisson distributions。例如:

import numpy
from scipy.stats import poisson

i = numpy.arange(10)
p = poisson(3)
print(p.pmf(i))

给予:

[ 0.04978707  0.14936121  0.22404181  0.22404181  0.16803136  0.10081881
  0.05040941  0.02160403  0.00810151  0.0027005 ]

【讨论】:

  • +1 表示scipy.stats,但 scipy 提供的阶乘函数仍将 inf 输出大参数。
  • 谢谢。我将生成泊松数作为在网络中生成数据包时间。如何使用此函数连续生成泊松数?
猜你喜欢
  • 2014-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-03
  • 1970-01-01
  • 1970-01-01
  • 2021-01-22
  • 1970-01-01
相关资源
最近更新 更多