I am getting the following unexpected result when I do arithmetic with small numbers in Python:
>>> sys.float_info
sys.float_info(max=1.797693134862
You have epsilon=2.220446049250313e-16
so it is normal that (1. - (1.e-17) ) = 1
because 1.e-17 < epsilon
.
it should be able to handle "large" small numbers like 1e-17, shouldn't it?
Not necessarily (it depends on the numbers). A float
cannot exactly represent either 1e-17
or 1-(1e-17)
. In the case of the latter, the nearest number that it can represent is 1
.
I suggest you read What Every Computer Scientist Should Know About Floating-Point Arithmetic.
First, let's review what epsilon
really is in the return value of sys.float_info
.
Epsilon (or
If you need this level of precision, consider the Decimal module
>>> decimal.Decimal(1.0)-decimal.Decimal('1.0e-17')
Decimal('0.999999999999999990')
>>> decimal.Decimal(1.0)-decimal.Decimal('1.0e-17')<decimal.Decimal(1.0)
True
And:
>>> decimal.Decimal(1.0)-decimal.Decimal('1.0e-17')<1.0
True
Careful with the last one though because you can get conversion errors.
Others have suggested What Every Computer Scientist Should Know About Floating-Point Arithmetic. and I also recommend Don’t Store That in a Float
you can handle those. note that
>>> 1.e-17 == 0
False
and
>>> 1.e-17 + 1.e-18
1.1e-17
you simply cannot handle 1-1e-17, because the mantissa won't fit in the finite precision
>>> from decimal import Decimal
>>> Decimal('1')-Decimal(str(10**-17)) < Decimal('1')
True
Use the decimal module, for that kind of accuracy!