Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 928
user171780 Avatar asked Nov 09 '19 22:11

user171780


People also ask

How does Python handle small numbers?

One solution is to work with logarithmic values which would increase the range of my float value. The problem is that I have to do a fft with these values, too, and therefore using the logarithmic approach is not usable (and using the Decimal -module neither).

How do you write small numbers in Python?

But you can't always use superscripts, so another way to show the same thing is E-notation. E-notation is just another way of writing scientific notation. For very small numbers, like 0.0000000000001752, a negative exponent is used. The scientific notation would be 1.752 x 10-13, and the E-notation would be 1.752e-13.

What is the smallest number that can be represented in Python?

The minimum value of 2.2250738585072014e-308 is a normal representation float value. You can get down to about 5e-324 with subnormal representation.

How do you handle a large number in Python?

Python supports a "bignum" integer type which can work with arbitrarily large numbers. In Python 2.5+, this type is called long and is separate from the int type, but the interpreter will automatically use whichever is more appropriate.


1 Answers

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

like image 56
ingvar Avatar answered Oct 19 '22 22:10

ingvar