[issue36028] Integer Division discrepancy with float
Tim Peters
report at bugs.python.org
Mon Feb 18 22:53:33 EST 2019
Tim Peters <tim at python.org> added the comment:
Thanks, Steven! I'll go on to suggest that the best intro to these issues for Python programmers is in Python's own tutorial:
https://docs.python.org/3/tutorial/floatingpoint.html
Raymond, `divmod(a, b)[0]` IS the mathematical `floor(a/b)`, where the latter is computed (as if) with infinite precision. Rounding `a/b` to a float _before_ taking the floor is quite different, and was never seriously considered for Python. For one thing, the result is ill-defined unless you control the rounding mode used by HW float division (4.0 / 0.4 == 10.0 only if the rounding mode is to-nearest/even or to-plus-infinity; it's 1 ULP less if to-minus-infinity or to-zero; then taking the floor gives 10 in the former cases but 9 in the latter). It makes scant sense for the result of // to depend on rounding mode: the very name - "floor division" - implies rounding is forced. More fundamentally,
a = (a // b)*b + (a % b)
is the invariant Guido was most keen to preserve. In any conforming C implementation (by the standard today, but by best practice at the time), fmod(4.0, 0.4) == 0.3999999999999998 on a box with 754 doubles, and Python had no interest in building its own idea of "mod" entirely from scratch. Given that, 4 // 0.4 has to return 9.
That said, C's fmod makes more sense for floats than Python's % (which latter makes more sense for integers than C's integer %), because fmod is always exact. Python's float % cannot be, because it retains the sign of the modulus: in, e.g., 1 % -1e100, there is no mathematical integer `n` such that the mathematical 1 + n*-1e100 is both negative and representable as a float.
>>> 1 % -1e100
-1e+100 # negative, but not exactly 1 + 1*-1e100
>>> math.fmod(1, -1e100)
1.0 # is exactly 1 + 0*-1e100, but not negative
In any case, none of this is going to change after 30 years ;-) For Python 3 I had thought Guido agreed to change a % b for floats to return an exact result (exactly equal to the mathematical a - q*b for some mathematical integer q) such that abs(a % b) <= abs(b)/2, which is most useful most often for floats. But that didn't happen.
----------
_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue36028>
_______________________________________
More information about the Python-bugs-list
mailing list