As the previous answerers have correctly pointed out, the fraction 0.05 = 1/20 cannot be exactly represented with a finite number of base-two digits. It works out to the repeating fraction 0.0000 1100 1100 1100... (much like 1/3 = 0.333... in familiar base-ten).
But this is not quite a complete answer to your question, because there's another bit of weirdness going on here:
>>> 1 / 0.05
20.0
>>> 1 // 0.05
19.0
Using the “true division” operator /
happens to give the expected answer 20.0
. You got lucky here: The rounding error in the division exactly cancels out the error in representing the value 0.05 itself.
But how come 1 // 0.05
returns 19? Isn't a // b
supposed to be the same as math.floor(a /b)
? Why the inconsistency between /
and //
?
Note that the divmod
function is consistent with the //
operator:
>>> divmod(1, 0.05)
(19.0, 0.04999999999999995)
This behavior can be explained by performing computing the floating-point division with exact rational arithmetic. When you write the literal 0.05
in Python (on an IEEE 754-compliant platform), the actual value represented is 3602879701896397 / 72057594037927936 = 0.05000000000000000277555756156289135105907917022705078125. This value happens to be slightly more than the intended 0.05, which means that its reciprocal will be slightly less.
To be precise, 72057594037927936 / 3602879701896397 = 19.999999999999998889776975374843521206126552300723564152465244707437044687...
So, //
and divmod
see an integer quotient of 19. The remainder works out to 0.04999999999999994726440633030506432987749576568603515625, which is rounded for display as 0.04999999999999995
. So, the divmod
answer above is in fact good to 53-bit accuracy, given the original incorrect value of 0.05
.
But what about /
? Well, the true quotient 72057594037927936 / 3602879701896397 isn't representable as a float
, so it must be rounded, either down to 20-2**-48
(an error of about 2.44e-15) or up to 20.0
(an error of about 1.11e-15). And Python correctly picks the more accurate choice, 20.0
.
So, it seems that Python's floating-point division is internally done with high enough precision to know that 1 / 0.05
(that's the float
literal 0.05
, not the exact decimal fraction 0.05), is actually less than 20, but the float
type in itself is incapable of representing the difference.
At this point you may be thinking “So what? I don't care that Python is giving a correct reciprocal to an incorrect value. I want to know how to get the correct value in the first place.” And the answer to that is either:
1 / 0.05
is20.0
, but1 // 0.05
is19.0
. – Indore//
is supposed to returnint
... – Yangyangtzepydoc(//)
– Oriint
,float
,Decimal
,complex
and so on. – Maiblepydoc '//'
orhelp('//')
, although I admit the result is of limited usefulness, apart from the precedence info. – Mycenaeandecimal.Decimal
. – Outcross