3

To illustrate my example

Try running:

print(1//0.1)
print(1/0.1)
print(int(1/0.1))

Output:

>>> print(1//0.1)
9.0
>>> print(1/0.1)
10.0
>>> print(int(1/0.1))
10

The result of 1//0.1 is both not an integer, and incorrect. The same applies with other numbers / test-cases. Is this behavior documented anywhere in python? I could not find anything relevant.

2
  • 3
    Apparently // is not actually integer division; it is what Python calls floor division. It is the result of performing the division and then rounding down. In floating point operations, this can cause some perverse effects; I suspect that 1/0.1 is actually something like 9.999999964, because many decimal numbers cannot be represented precisely as a power of two, which is what a floating point number is. Read Is floating point math broken? for more information. Commented May 13, 2022 at 20:41
  • Related: stackoverflow.com/questions/72052228/… Commented May 13, 2022 at 21:14

1 Answer 1

7

It's actually called __floordiv__ according to the data model. The docs for divmod mention the relation to math.floor:

[...] For floating point numbers the result is (q, a % b), where q is usually math.floor(a / b) but may be 1 less than that. In any case q * b + a % b is very close to a, [...]

Hence, if q, r = divmod(a, b) then it holds that q*b + r == a and q == a//b.

>>> a, b = 1, 0.1
>>> q, r = divmod(a, b)
>>> q*b + r == a
True
>>> a//b == q
True

So the only guarantee here is that q*b + r == a holds.


As for 1.0 // 0.1 yielding 9.0 it is because FP numbers are represented internally in base 2, and 0.1 is not a "round" number, but actually, larger than the "mathematical 0.1":

In [79]: f"{0.1:.20f}"
Out[79]: '0.10000000000000000555'
Sign up to request clarification or add additional context in comments.

3 Comments

@a_guest - I edited the text to add an example of what is going on with 0.1 to your excellent answer - it would not be worth to add another answer with just this snippet, and I think it should be more visible than a comment. Feel free to edit it back/change.
nitpick, this op is handled by float.__rfloordiv__ not by int.__floordiv__.
@jsbueno Thanks. Indeed, CPython chooses the mathematically correct way given that is has access to only the limited numerical precision that the numeral 0.1 has been converted to (at this point, Python does not have any information about the original numerals anymore). So it does its best by working with the numbers that the float objects correspond to.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.