For your use case, use integer arithmetic. There is a simple technique for converting integer floor division into ceiling division:
items = 102
boxsize = 10
num_boxes = (items + boxsize - 1) // boxsize
Alternatively, use negation to convert floor division to ceiling division:
num_boxes = -(items // -boxsize)
Answer from Raymond Hettinger on Stack OverflowFor your use case, use integer arithmetic. There is a simple technique for converting integer floor division into ceiling division:
items = 102
boxsize = 10
num_boxes = (items + boxsize - 1) // boxsize
Alternatively, use negation to convert floor division to ceiling division:
num_boxes = -(items // -boxsize)
Negate before and after?
>>> -(-102 // 10)
11
No, but you can use upside-down floor division:¹
def ceildiv(a, b):
return -(a // -b)
This works because Python's division operator does floor division (unlike in C, where integer division truncates the fractional part).
Here's a demonstration:
>>> from __future__ import division # for Python 2.x compatibility
>>> import math
>>> def ceildiv(a, b):
... return -(a // -b)
...
>>> b = 3
>>> for a in range(-7, 8):
... q1 = math.ceil(a / b) # a/b is float division
... q2 = ceildiv(a, b)
... print("%2d/%d %2d %2d" % (a, b, q1, q2))
...
-7/3 -2 -2
-6/3 -2 -2
-5/3 -1 -1
-4/3 -1 -1
-3/3 -1 -1
-2/3 0 0
-1/3 0 0
0/3 0 0
1/3 1 1
2/3 1 1
3/3 1 1
4/3 2 2
5/3 2 2
6/3 2 2
7/3 3 3
Why this instead of math.ceil?
math.ceil(a / b) can quietly produce incorrect results, because it introduces floating-point error. For example:
>>> from __future__ import division # Python 2.x compat
>>> import math
>>> def ceildiv(a, b):
... return -(a // -b)
...
>>> x = 2**64
>>> y = 2**48
>>> ceildiv(x, y)
65536
>>> ceildiv(x + 1, y)
65537 # Correct
>>> math.ceil(x / y)
65536
>>> math.ceil((x + 1) / y)
65536 # Incorrect!
In general, it's considered good practice to avoid floating-point arithmetic altogether unless you specifically need it. Floating-point math has several tricky edge cases, which tends to introduce bugs if you're not paying close attention. It can also be computationally expensive on small/low-power devices that do not have a hardware FPU.
¹In a previous version of this answer, ceildiv was implemented as return -(-a // b) but it was changed to return -(a // -b) after commenters reported that the latter performs slightly better in benchmarks. That makes sense, because the dividend (a) is typically larger than the divisor (b). Since Python uses arbitrary-precision arithmetic to perform these calculations, computing the unary negation -a would almost always involve equal-or-more work than computing -b.
Solution 1: Convert floor to ceiling with negation
def ceiling_division(n, d):
return -(n // -d)
Reminiscent of the Penn & Teller levitation trick, this "turns the world upside down (with negation), uses plain floor division (where the ceiling and floor have been swapped), and then turns the world right-side up (with negation again)"
Solution 2: Let divmod() do the work
def ceiling_division(n, d):
q, r = divmod(n, d)
return q + bool(r)
The divmod() function gives (a // b, a % b) for integers (this may be less reliable with floats due to round-off error). The step with bool(r) adds one to the quotient whenever there is a non-zero remainder.
Solution 3: Adjust the numerator before the division
def ceiling_division(n, d):
return (n + d - 1) // d
Translate the numerator upwards so that floor division rounds down to the intended ceiling. Note, this only works for integers.
Solution 4: Convert to floats to use math.ceil()
def ceiling_division(n, d):
return math.ceil(n / d)
The math.ceil() code is easy to understand, but it converts from ints to floats and back. This isn't very fast and it may have rounding issues. Also, it relies on Python 3 semantics where "true division" produces a float and where the ceil() function returns an integer.
Integer ceiling divide - Ideas - Discussions on Python.org
Why is 11//2 = 5?
Why Python's Integer Division Floors
How to round up the answer of an integer division?
Videos
Fresh beginner here.
I understand // rounds the resulting number to the closest integer. I guess the type "rounding" is a different thing, but its said in the post linked below that Python 3 uses 'ties to even' rule. I'm wondering why 5.5 rounds down rather than up? Stuck in the theory, any clarification is appreciated - cheers!!
https://www.reddit.com/r/learnpython/comments/92ne2s/why_does_round05_0/?utm_source=share&utm_medium=web2x&context=3