pythonmathdecimalunderflow

Handling very very small numbers in Python


I need to multiply about 1e6 numbers that are of the order of 0.01. The expected result is of order 1e-100000000. Obviously the typical floating-point arithmetic cannot handle this.

Doing some research on the web I found the decimal library which seems to fix this problem. However it appears to have limitations that make it useless for my needs:

>>> Decimal('.01')**Decimal('1e5') # Seems to handle this
Decimal('1E-200000')
>>> Decimal('.01')**Decimal('1e5')*Decimal('1E200000') # Yeah! It works!
Decimal('1')
>>> Decimal('.01')**Decimal('1e6') # This result is strange...
Decimal('0E-1000026')
>>> Decimal('.01')**Decimal('1e6')*Decimal('0E1000026') # Wrong result
Decimal('0')

Does anyone know any solution to this?


Solution

  • Your result is incorrect because decimal has precision too (decimal is fixed point math), so you get underflow issue here too:

    Decimal('.01')**Decimal('1e6')
    

    Decimal('0E-1000026')

    But:

    getcontext().prec = 1000000000   # sets precision to 1000000000
    Decimal('.01')**Decimal('1e6')
    

    Decimal('1E-2000000')

    You can fix your issue by manualy setting precision as in example above or manually calculate powers, for example:

    Decimal('.01')**Decimal('1e6')
    

    can be converted to

    Decimal('1e-2') ** Decimal('1e6')
    

    and later to

    1 ** ((-2) ** 1e6) = 1 ** (-2000000)
    

    Decimal module documentation