According to PEP 238: "floor division will be implemented in all the Python numeric types, and will have the semantics of: a // b == floor(a/b) except that the result type will be the common type into which a and b are coerced before the operation." But consider the following cases in Python 3.6.3: >>> 0.9//0.1 8.0 >>> 0.8//0.1 8.0 >>> import math >>> math.floor(0.9/0.1) 9 >>> math.floor(0.8/0.1) 8 Am I missing something?
That does look at first glance like a bug in // to me. 0.9/0.1 is correctly rounded to 9.0 exactly, so flooring it should return 9 (as it does): # Python 3.5 on Linux py> 0.9/0.1 == 9 True py> math.floor(0.9/0.1) 9 So I too would expect that 0.9//0.1 should evaluate as 9, not 8.
This is the result of multiple roundings. 0.9 and 0.1 can't be represented exactly as floats. They are approximated by binary fractions. >>> from fractions import Fraction >>> Fraction(0.9) Fraction(8106479329266893, 9007199254740992) >>> Fraction(0.1) Fraction(3602879701896397, 36028797018963968) The result of the division of these fractions can't be represented as a float too. >>> Fraction(0.9)/Fraction(0.1) Fraction(32425917317067572, 3602879701896397) >>> Fraction(0.9)/Fraction(0.1) - 9 Fraction(-1, 3602879701896397) >>> float(Fraction(0.9)/Fraction(0.1) - 9) -2.7755575615628914e-16 >>> 9 + float(Fraction(0.9)/Fraction(0.1) - 9) 9.0 It is slightly smaller than 9, but the nearest float value is 9.0. Thus the result of the division is rounded up to 9.0. A similar issue already was opened several months ago. I don't remember the number.
This report appears to be the same: https://bugs.python.org/issue27463 One other thing to note: the Python docs are sometimes unclear about whether expressions are intended to be interpreted as Python code or as mathematical expressions. In: """ floor division will be implemented in all the Python numeric types, and will have the semantics of: a // b == floor(a/b) """ note that it did _not_ say `math.floor(a/b)`. `floor(a/b)` here is intended to be read as a mathematical (infinitely precise) specification. As can be inferred from the output Serhiy posted, after the Python a = 0.9 b = 0.1 the infinitely precise value of `a/b` is a tiny bit less than 9, so the infinitely precise value of `floor(a/b)` is exactly 8. Which is what the Python `a // b` returns. Personally, I wish Python 3 had changed the meaning of `//` (and `divmod()` and `%` - the three are deeply related) for floats, but too late for that now :-)
History
Date
User
Action
Args
2022-04-11 14:58:56
admin
set
github: 76724
2018-01-13 03:17:59
tim.peters
set
messages: +
2018-01-13 00:07:48
serhiy.storchaka
set
status: open -> closednosy: + serhiy.storchakamessages: + resolution: not a bugstage: resolved