This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author tim.peters
Recipients Au Vo, mark.dickinson, remi.lapeyre, rhettinger, skrah, steven.daprano, tim.peters
Date 2019-02-19.03:53:33
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1550548413.95.0.748950141296.issue36028@roundup.psfhosted.org>
In-reply-to
Content
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.
History
Date User Action Args
2019-02-19 03:53:33tim.peterssetrecipients: + tim.peters, rhettinger, mark.dickinson, steven.daprano, skrah, remi.lapeyre, Au Vo
2019-02-19 03:53:33tim.peterssetmessageid: <1550548413.95.0.748950141296.issue36028@roundup.psfhosted.org>
2019-02-19 03:53:33tim.peterslinkissue36028 messages
2019-02-19 03:53:33tim.peterscreate