New modulo operator to get both quotient and remainder

Hello,

I was doing some computation and sometimes we have to get quotient and remainder of a value, for instance

quotient = value // divider
remainder = value % divider

So I was thinking maybe we could introduce a new operator to get both like

quotient, remainder = value %% divider

but I don’t know how useful this would be. Are there any people out there which think it would be helpful?

The built in divmod does this.

2 Likes

It does somewhat slowly, though. A benchmark:

 40.99 ±  0.15 ns  q, r = x // y, x % y
 40.92 ±  0.09 ns  x // y; x % y
 68.08 ±  0.30 ns  q, r = divmod(x, y)
 66.14 ±  0.42 ns  q, r = dm(x, y)

Python: 3.11.4 (main, Sep  9 2023, 15:09:21) [GCC 13.2.1 20230801]

Edit: Hmm, part of the slowness is from creating the tuple, which the operator would likely also do. So how fast would the operator be? I don’t see a way to find out other than implementing it…

Benchmark script
from timeit import timeit
from statistics import mean, stdev
import sys

setup = 'x, y, dm = 42, 23, divmod'
codes = [
    'q, r = x // y, x % y',
    'x // y; x % y',
    'q, r = divmod(x, y)',
    'q, r = dm(x, y)',
]

times = {c: [] for c in codes}
def stats(c):
    ts = [t * 1e9 for t in sorted(times[c])[:5]]
    return f'{mean(ts):6.2f} ± {stdev(ts):5.2f} ns '
for _ in range(100):
    for c in codes:
        t = timeit(';'.join([c] * 100), setup, number=10**3) / 1e5
        times[c].append(t)
for c in codes:
    print(stats(c), c)

print('\nPython:', sys.version)

Attempt This Online!

I’d prefer /% or //% though, to indicate both things it does and the order of the results:

quotient, remainder = value /% divider
quotient, remainder = value //% divider

About usefulness, @mdickinson wrote about divmod a while ago.

divmod has been around much longer than the // operator. From a readability perspective using // and % is probably better. That they are faster to boot (mostly from saving function call overhead I suspect) is just a bonus. Think of divmod as an appendix, not really useful anymore, but lingering around from a time when it was necessary.

When was it necessary for what?

Hmmm… that’s a good question. My brain wasn’t fully caffeinated when I responded. While // is newer than divmod, the / operator used to perform integer division. So, x / y, x % y as a readability improvement has always been available.

Still, it is quite possible that divmod was quite a bit faster than x / y, x % y once upon a time. The interpreter has undergone a huge amount of optimization over the past 25 years or so. Still, removing divmod because it’s now slower than the paired expressions [edit: probably] wasn’t deemed worthwhile because it would break functioning code.

Plus, there’s a significant readability boost when doing chained divisions like with time conversions:

minutes, seconds = divmod(target_time - time(), 60)
hours, minutes = divmod(minutes, 60)
days, hours = divmod(hours, 24)

If you had to repeat the expression left and right, there’d be the risk of desynchronization bugs, but with divmod it’s obvious there can’t be.

(And believe you me, it is a PAIN to have to figure out what’s going on when you had something like days = hours / 60; hours %= 24 and you’re staring at bizarre output in total confusion.)

2 Likes

Its can be replaced exactly for int args but not for float args I recall.
And as Chris shows it is often clearer to get the pair back in one go.