web-dev-qa-db-fra.com

OverflowError: long int too large to convert to float in python

J'ai essayé de calculer la distribution de poisson en python comme ci-dessous:

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

idx varie de 0

Mais j'ai eu OverflowError: long int too large to convert to float

J'ai essayé de convertir depart en float mais aucun résultat.

21
user2312186

Les factorielles deviennent grandes très rapidement :

>>> math.factorial(170)
7257415615307998967396728211129263114716991681296451376543577798900561843401706157852350749242617459511490991237838520776666022565442753025328900773207510902400430280058295603966612599658257104398558294257568966313439612262571094946806711205568880457193340212661452800000000000000000000000000000000000000000L

Notez le L; la factorielle de 170 est toujours convertible en flotteur:

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

mais la factorielle suivante est trop grande:

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

Vous pourriez utiliser le module decimal ; les calculs seront plus lents, mais la classe Decimal() peut gérer les factorielles de cette taille:

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

Vous devrez utiliser les valeurs de Decimal() partout:

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

Lorsque idx devient grand, le math.pow et/ou le math.factorial deviendra incroyablement volumineux et ne pourra pas être converti en valeur flottante (idx=1000 déclenche l'erreur sur ma machine 64 bits). Vous ne voudrez pas utiliser la fonction math.pow car elle déborde plus tôt que la fonction **, car il essaie de conserver une précision plus élevée en effectuant une conversion flottante plus tôt. En outre, vous pouvez encapsuler chaque appel de fonction dans un objet Decimal pour une meilleure précision.

Une autre approche lorsqu'il s'agit de très grands nombres consiste à travailler à l'échelle logarithmique. Prenez le journal de chaque valeur (ou calculez la version du journal de chaque valeur) et effectuez toutes les opérations requises avant de prendre l'exponentiation des résultats. Cela permet à vos valeurs de quitter temporairement l'espace de domaine flottant tout en calculant avec précision une réponse finale qui se trouve dans le domaine flottant.

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)

Cela reste dans le domaine du journal jusqu'à la fin afin que vos chiffres puissent devenir très, très gros avant que vous ne rencontriez des problèmes de débordement.

5
Pyrce

Essayez d'utiliser la bibliothèque décimale. Il prétend soutenir une précision arbitraire.
from decimal import Decimal

De plus, vous n'avez pas besoin d'utiliser math.pow. pow est intégré.

3
xylon97

Le module scipy pourrait vous aider.

scipy.misc.factorial est une fonction factorielle qui peut utiliser l'approximation de la fonction gamma pour calculer la factorielle et renvoie le résultat en virgule flottante.

import numpy
from scipy.misc import factorial

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

Donne:

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

Il y a aussi un module pour calculer les distributions de Poisson . Par exemple:

import numpy
from scipy.stats import poisson

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

Donne:

[ 0.04978707  0.14936121  0.22404181  0.22404181  0.16803136  0.10081881
  0.05040941  0.02160403  0.00810151  0.0027005 ]
1
Charles Brunet