web-dev-qa-db-ja.com

OverflowError:long intが大きすぎてpythonでfloatに変換できない

以下のように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に変換しようとしましたが、結果はありませんでした。

21
user2312186

階乗は大きくなります本当に速い

_>>> math.factorial(170)
7257415615307998967396728211129263114716991681296451376543577798900561843401706157852350749242617459511490991237838520776666022565442753025328900773207510902400430280058295603966612599658257104398558294257568966313439612262571094946806711205568880457193340212661452800000000000000000000000000000000000000000L
_

Lに注意してください。 170の階乗はまだfloatに変換可能です:

_>>> 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
_

あなたはcoulddecimal 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)
_
25
Martijn Pieters

idxが大きくなると、math.powおよび/またはmath.factorialが異常に大きくなり、浮動値に変換できなくなります(idx=1000は64でエラーをトリガーします)ビットマシン)。 math.pow関数は、組み込みの**演算子よりも早くオーバーフローするため、float変換を使用してより高い精度を維持しようとするため、使用しない方がよいでしょう。さらに、各関数呼び出しをDecimalオブジェクトでラップして、精度を高めることができます。

非常に大きな数を扱う場合のもう1つのアプローチは、ログスケールで作業することです。すべての値のログを取得(または各値のログバージョンを計算)し、結果のべき乗を取得する前に必要なすべての操作を実行します。これにより、フローティングドメイン内にある最終的な回答を正確に計算しながら、値を一時的にフローティングドメイン空間から残すことができます。

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)

これは最後までログドメインにとどまるため、オーバーフローの問題が発生する前に数値が非常に大きくなる可能性があります。

5
Pyrce

Decimalライブラリを使用してみてください。任意の精度をサポートすると主張しています。
from decimal import Decimal

また、math.powを使用する必要はありません。 powは組み込みです。

3
xylon97

scipyモジュールが役立ちます。

scipy.misc.factorial は、ガンマ関数近似を使用して階乗を計算できる階乗関数であり、浮動小数点を使用して結果を返します。

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 ]

ポアソン分布を計算するモジュール もあります。例えば:

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
Charles Brunet