It’s one of those tricky topics where on its own the answer to “Should we group the existing discrete arithmetic functions into a new dedicated standard library module?” is fairly obviously “No, it’s too much work for not enough practical benefit” (thus making a standalone discussion very short).
However, at some point, some proposal is going to have to hit the threshold of “OK, this is getting silly, we need a dedicated place to access and document these, separate from math and the builtin namespace”. Until then, we’re going to have the “math isn’t the right place, but it’s the best option we have readily available” discussion each time.
I guess a dedicated thread would at least provide a place to summarise the full list of relevant APIs that already exist in the stdlib (using @madeleineth’s list in Integer ceiling divide - #13 by madeleineth as a starting point).
As a datapoint on my claim that codebases tend to end up with multiple copies of the function, I found three variations in cpython (2/3 on the C side), two of them confusing enough that the authors felt the need to comment what the expression meant.
If ceildiv() is added to stdlib, we should add also a function for division with rounding to the nearest integer (like _pydatetime._divide_and_round() or _PyLong_DivmodNear()). It may be useful in more cases than rounding up.
The initial gcd() implementation was in the fractions module. It contains also an implementation for division with rounding to the nearest integer, but not as a public function.
Now that math.integer will be implemented in Python 3.15, perhaps we can continue this thread.
Question:
If mod() gives the remainder of floordiv(), should we consider ceilmod() for the spares of ceildiv()? I.e. for the ‘x objects and containers size y’ of OP, ceildiv(x, y) gives the number of containers and ceilmod(x, y) tells how many empty slots remain.
def ceildiv(m, n): return -(m // -n)
def ceilmod(m, n): return -(m % -n)
for m in tests:
for n in tests:
assert n == 0 or ceildiv(m, n) * n - ceilmod(m, n) == m, "new invariant"
assert n == 0 or floordiv(m, n) * n + mod(m, n) == m, "regular invariant"
Orthogonality would suggest so, but this path risks growth with ceildivmod(), roundmod(), and rounddivmod().
OTOH, Java has math.ceilMod() with an opposite sign:
def ceildiv(m, n): return -(m // -n)
def ceilmod(m, n): return (m % -n)
for m in tests:
for n in tests:
assert n == 0 or ceildiv(m, n) * n + ceilmod(m, n) == m, "same invariant as floor"
assert n == 0 or floordiv(m, n) * n + mod(m, n) == m, "regular invariant"
To avoid confusion, following this definition seems advisable (even if positive operands then give negative outcomes).
I’ve been using ceildiv recently for the purpose of
I called it ceil_div because I’m overly verbose in my naming sometimes . I’m speciously reading the c in cdiv or c_div like the C programming language, as though it has only finite precision compared to Python’s infinite precision. I think ceildiv would be the best name, located at math.integer.ceildiv.
As for the implementation I must admit I googled it for the sake of getting a computationally efficient one.
is what I’m using but I haven’t even considered how it should be implemented for negative numbers. So to reply to
I do think the use case is common enough for x>=0 and y>=1, and makes things less error prone for the end user if the implementation is taken care of by the stdlib.
It’s just the behavior for negative x or y that I’d have to see different real-use cases / implementations for. Like we can’t just think about x = qy + r with 0 <= r < b Euclid’s Algorithm style when y < 0; we usually make x and y positive and find the gcd of those.
Mathematically there’s no confusion here. The ceiling of a real number x is the smallest integer \ge x (“round toward +\infty”) And x/y is defined for all y other than 0. Put those together, and for any y \ne 0, ceildiv(x, y) should be the mathematical cailing(x / y) as if computed with infinite precision.
There are several ways to try to compute that sticking to integer arithmetic, but they’re either non-obvious, or broken for some cases.
I’vw personally only had uses for both arguments \ge 0
No obvious “at first glance”, but easy to remember once someone has grasped the right mental geometric picture. I’ve encountered many people to whom the latter was an epiphany .
Note: if you have n items to distribute across bins each with the capacity to hold c items, then the minimum number of bins needed is caildiv(n, c). If you want to know the total capacity of those bins, then c * ceildiv(n, c) does the tri\ck.
But there’s a faster way that’s also
not obvious at first glance; but
easy to remember once you picture it the right way.
Namely n + (-n % c)
Since % in Python is always \ge 0 when the divisor is postitive, the sum is always at least as large as n. But viewing the sum modulo c, it’s
(n + (-n % c)) mod c =
(n + -n) mod c =
0
Which is an easy and general way to round up to the closest multiple of c.
For example, to round up b bytes to a 16-byte boundary,