This is one of the subtle points of IEEE-754 arithmetic. When you write:
>>> 1/3
0.3333333333333333
the number you see printed is a "rounded" version of the number that is internally stored as the result of 1/3
. It's just what the Double -> String conversion in the printing process decided to show you. But you already knew that.
Now you can ask, is there a way to find out what the difference is? Yes, use the fractions
module:
>>> from fractions import Fraction
>>> Fraction(1, 3) - Fraction(1/3)
Fraction(1, 54043195528445952)
Ah, that's interesting. So it is slightly less than the actual value, and the difference is 1 / 54043195528445952
. This is, of course, expected.
So, what happens when you "add" two of these together. Let's see:
>>> Fraction(2,3) - Fraction(1/3+1/3)
Fraction(1, 27021597764222976)
Again, you're close to 2/3
rds, but still not quite there. Let's do the addition one more time:
>>> Fraction(1,1) - Fraction(1/3+1/3+1/3)
Fraction(0, 1)
Bingo! with 3 of them, the representation is exactly 1
.
Why is that? Well, in each addition you get a number that's close to what you think the answer should be, but the internal rounding causes the result to become a close-by number that's not what you had in mind. With three additions what your intuition tells you and what the internal rounding does match up.
It is important to emphasize that the addition 1/3 + 1/3 + 1/3
does not produce a 1
; it just produces an internal value whose closest representation as an IEEE-754 double-precision floating point value is 1
. This is a subtle but important difference. Hope that helps!