OverflowError: long int too large для преобразования в 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, но никаких результатов.

Ответы

Ответ 1

Факториалы становятся большими реальными:

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

Вы можете использовать модуль decimal; вычисления будут медленнее, но класс 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)

Ответ 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

Попробуйте использовать десятичную библиотеку. Он утверждает, что поддерживает произвольную точность.
from decimal import Decimal

Кроме того, вам не нужно использовать math.pow. pow встроен.

Ответ 4

Модуль 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 ]