factorial - OverflowError:largo int demasiado grande para convertirlo en floth en python




(5)

Los factoriales se hacen grandes muy rápido :

>>> math.factorial(170)
7257415615307998967396728211129263114716991681296451376543577798900561843401706157852350749242617459511490991237838520776666022565442753025328900773207510902400430280058295603966612599658257104398558294257568966313439612262571094946806711205568880457193340212661452800000000000000000000000000000000000000000L

Tenga en cuenta la L ; El factorial de 170 es todavía convertible a un flotador:

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

Pero el siguiente factorial es demasiado 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

Podrías usar el módulo decimal ; los cálculos serán más lentos, pero la clase Decimal() puede manejar factoriales de este tamaño:

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

Tendrás que usar valores Decimal() largo de:

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)

Intenté calcular la distribución de poisson en python como se muestra a continuación:

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

IDX oscila entre 0

Pero tengo OverflowError: long int too large to convert to float

Traté de convertir la salida para float pero no hay resultados.


El módulo scipy podría ayudarte.

scipy.misc.factorial es una función factorial que puede utilizar la aproximación de la función gamma para calcular el factorial y devuelve el resultado utilizando puntos flotantes.

import numpy
from scipy.misc import factorial

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

Da:

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

También hay un módulo para calcular las distribuciones de Poisson . Por ejemplo:

import numpy
from scipy.stats import poisson

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

Da:

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

Trate de usar la biblioteca decimal. Afirma apoyar la precisión arbitraria.
from decimal import Decimal

Además, no es necesario utilizar math.pow . pow está incorporado.


Cuando idx se haga grande, math.pow y / o math.factorial se volverán increíblemente grandes y no podrán convertirse a un valor flotante ( idx=1000 provoca el error en mi máquina de 64 bits). No querrá usar la función math.pow ya que se desborda antes que el operador ** integrado porque trata de mantener una mayor precisión al hacer una conversión flotante antes. Además, puede ajustar cada llamada de función en un objeto Decimal para una mayor precisión.

Otro enfoque cuando se trata de números muy grandes es trabajar en la escala de registro. Tome el registro de cada valor (o calcule la versión de registro de cada valor) y realice todas las operaciones requeridas antes de tomar la exponenciación de los resultados. Esto permite que sus valores dejen temporalmente el espacio del dominio flotante mientras aún computan con precisión una respuesta final que se encuentra dentro del dominio flotante.

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))
...
math.exp(result)

Esto permanece en el dominio de registro hasta el final, por lo que sus números pueden ser muy, muy grandes antes de que tenga problemas de desbordamiento.


La respuesta aceptada sugiere un reemplazo directo para xrange, pero solo cubre un caso. Aquí hay un reemplazo más general y directo.

def custom_range(start=0,stop=None,step=1):
    '''xrange in python 2.7 fails on numbers larger than C longs.
    we write a custom version'''
    if stop is None:
        #handle single argument case. ugly...
        stop = start
        start = 0
    i = start
    while i < stop:
        yield i
        i += step

xrange=custom_range




python overflow factorial