classification
Title: Add math.remainder operation
Type: enhancement Stage: resolved
Components: Extension Modules Versions: Python 3.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: mark.dickinson, rhettinger, serhiy.storchaka
Priority: normal Keywords:

Created on 2017-04-01 14:32 by mark.dickinson, last changed 2017-04-05 17:36 by mark.dickinson. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 950 merged mark.dickinson, 2017-04-01 14:38
Messages (7)
msg290985 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2017-04-01 14:32
IEEE 754, the C99 standard, the Decimal IBM standard and Java all support/specify a 'remainder-near' operation. Apart from being standard, this has a number of useful applications:

1. Argument reduction in numerical algorithms: it's common to want to reduce to a range [-modulus/2, modulus/2] rather than [0, modulus).
2. Particular case of the above: reduction of angles to lie in the range [-pi, pi]
3. Rounding a float x to the nearest multiple of y. This is a much-asked StackOverflow question, and the standard answer of y * round(x / y) risks introducing floating-point error and so can give incorrect results in corner cases. With a remainder operation, it's trivial to do this correctly: x - remainder(x, y) gives the closest representable float to the closest integer multiple of y to x.

remainder(x, y) has some nice properties: it's *always* exactly representable (unlike x % y), it satisfies the symmetry remainder(-x, y) == -remainder(x, y), and it's periodic with period 2*y.

I have a patch, and will make a PR shortly.
msg290987 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-04-01 15:08
See also Decimal.remainder_near and _PyLong_DivmodNear. Shouldn't the new function be named math.remainder_near?

In many cases the function that returns the nearest integer quotient is useful. See Fraction.__round__, datetime._divide_and_round, _pydecimal._div_nearest, etc.
msg290988 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2017-04-01 15:17
> Shouldn't the new function be named math.remainder_near?

Not clear. :-) I'd prefer to keep the name that's consistent with both C and IEEE 754. (We already have plenty of naming differences between Decimal and math; attempting to reconcile them is likely futile.)

FTR:

IEEE 754: remainder
C99: remainder
IBM Decimal spec: remainder-near
Java: IEEEremainder
.NET: IEEERemainder
msg290989 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2017-04-01 15:18
> In many cases the function that returns the nearest integer quotient is useful.

Agreed, but I'd like to keep the scope of this issue small for now: we're simply wrapping / implementing another C99 math.h function.
msg290990 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2017-04-01 15:25
FTR, I don't have strong opinions on the name: I could be persuaded by any of `remainder`, `remainder_near` or `ieee_remainder`. I find `ieee_remainder` somewhat more informative than `remainder_near`.
msg290991 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2017-04-01 15:41
> I'd prefer to keep the name that's consistent with both C and IEEE 754.

+1  

Also, the decimal module names are a poor guide.  Its usability has been impaired by opaque naming (i.e. needing to use quantize() when you want to round to a fixed number of places).
msg291188 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2017-04-05 17:34
New changeset a0ce375e10b50f7606cb86b072fed7d8cd574fe7 by Mark Dickinson in branch 'master':
bpo-29962: add math.remainder (#950)
https://github.com/python/cpython/commit/a0ce375e10b50f7606cb86b072fed7d8cd574fe7
History
Date User Action Args
2017-04-05 17:36:36mark.dickinsonsetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2017-04-05 17:34:29mark.dickinsonsetmessages: + msg291188
2017-04-01 15:41:23rhettingersetnosy: + rhettinger
messages: + msg290991
2017-04-01 15:25:02mark.dickinsonsetmessages: + msg290990
2017-04-01 15:18:44mark.dickinsonsetmessages: + msg290989
2017-04-01 15:17:28mark.dickinsonsetmessages: + msg290988
2017-04-01 15:08:42serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg290987
2017-04-01 14:38:52mark.dickinsonsetpull_requests: + pull_request1132
2017-04-01 14:32:38mark.dickinsoncreate