Why is the result of below code 0 in python3?
a = "4.15129406851375e+17"
a = float(a)
b = "415129406851375001"
b = float(b)
a-b
Why is the result of below code 0 in python3?
a = "4.15129406851375e+17"
a = float(a)
b = "415129406851375001"
b = float(b)
a-b
This happens because both 415129406851375001
and 4.15129406851375e+17
are greater than the integer representational limits of a C double
(which is what a Python float
is implemented in terms of).
Typically, C double
s are IEEE 754 64 bit binary floating point values, which means they have 53 bits of integer precision (the last consecutive integer values float
can represent are 2 ** 53 - 1
followed by 2 ** 53
; it can't represent 2 ** 53 + 1
). Problem is, 415129406851375001
requires 59 bits of integer precision to store ((415129406851375001).bit_length()
will provide this information). When a value is too large for the significand (the integer component) alone, the exponent component of the floating point value is used to scale a smaller integer value by powers of 2 to be roughly in the ballpark of the original value, but this means that the representable integers start to skip, first by 2 (as you require >53 bits), then by 4 (for >54 bits), then 8 (>55 bits), then 16 (>56 bits), etc., skipping twice as far between representable values for each bit of magnitude you have that can't be represented in 53 bits.
In your case, both numbers, converted to float
, have an integer value of 415129406851374976
(print(int(a), int(b))
will show you the true integer value; they're too large to have any fractional component), having lost precision in the low digits.
If you need arbitrarily precise base-10 floating point math, replace your use of float
with decimal.Decimal
(conveniently, your values are already strings, so you don't risk loss of precision between how you type a float
and the actual value stored); the default precision will handle these values, and you can increase it if you need larger values. If you do that, you get the behavior you expected:
from decimal import Decimal as Dec # Import class with shorter namea = "4.15129406851375e+17"
a = Dec(a) # Convert to Decimal instead of float
b = "415129406851375001"
b = Dec(b) # Ditto
print(a-b)
which outputs -1
. If you echoed it in an interactive interpreter instead of using print
, you'd see Decimal('-1')
, which is the repr
form of Decimal
s, but it's numerically -1
, and if converted to int
, or stringified via any method that doesn't use the repr
, e.g. print
, it displays as just -1
.
Try it online!