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?
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).
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.
The minimum value of 2.2250738585072014e-308 is a normal representation float value. You can get down to about 5e-324 with subnormal representation.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With