在 Python 中是否存在相当于//运算符的上限?

我发现了 Python 中的 //操作符,它在 Python 3中用 floor 进行除法。

是否存在一个用 ceil 分割的算符?(我知道 /操作符,它在 Python 3中进行浮点除法。)

129708 次浏览

没有用细胞分割的操作符。你需要使用 import mathmath.ceil

你可以用 x除以 d,例如 (x + 4) // 5

你也可以直接内联地做

((foo - 1) // bar) + 1

在 python3中,这比强制浮点除法和调用 ceil ()只快了一个数量级,前提是您关心速度。你不应该这么做,除非你已经通过使用证明你需要这么做。

>>> timeit.timeit("((5 - 1) // 4) + 1", number = 100000000)
1.7249219375662506
>>> timeit.timeit("ceil(5/4)", setup="from math import ceil", number = 100000000)
12.096064013894647

注意,math.ceil 的精度限制为53位。如果使用的是大整数,则可能得不到精确的结果。

Gmpy2库提供了使用上限舍入的 c_div函数。

免责声明: 我维护 gmpy2。

没有,但你可以使用倒置的地板划分: 1

def ceildiv(a, b):
return -(a // -b)

这是因为 巨蟒的部 T 是地板部 T(与 C 语言不同,在 C 语言中整数除法截断小数部分)。

这里有一个示范:

>>> 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

为什么是这个而不是 Math.ceil?

math.ceil(a / b)可以悄悄地产生不正确的结果,因为它引入了浮点错误。例如:

>>> 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!

一般来说,除非您特别需要,否则最好完全避免使用浮点算术。浮点数学有几个棘手的边缘情况,如果您没有密切关注,它往往会引入 bug。在没有硬件 FPU 的小型/低功耗设备上,它的计算开销也很大。


1在这个答案的前一个版本中,ceildiv 被实现为 return -(-a // b),但是在评论者报告说后者在基准测试中表现稍好后,它被改为 return -(a // -b)。这是有道理的,因为股息()通常大于除数(B)。由于 Python 使用高精度计算来执行这些计算,因此计算一元负 -a几乎总是比计算 -b涉及等量或更多的工作。

解决方案1: 用否定将地板转换为天花板

def ceiling_division(n, d):
return -(n // -d)

让人想起 Penn & Teller 的悬浮魔术,它“颠倒世界(用否定) ,使用普通的地板划分(天花板和地板交换) ,然后把世界正面朝上(再用否定)”

解决方案2: 让 divmod ()完成这项工作

def ceiling_division(n, d):
q, r = divmod(n, d)
return q + bool(r)

< em > divmod () 函数为整数赋予 (a // b, a % b)(由于舍入错误,浮点数的可靠性可能较低)。只要有非零余数,使用 bool(r)的步骤就会将1加到商上。

解决方案3: 在除法之前调整分子

def ceiling_division(n, d):
return (n + d - 1) // d

向上翻译分子,使楼层分割四舍五入到预期的天花板。注意,这只适用于整数。

解决方案4: 转换为 float 以使用 math.ceil ()

def ceiling_division(n, d):
return math.ceil(n / d)

Math.ceil ()代码很容易理解,但是它可以从 int 转换为 float 和 back。这不是很快,可能有舍入问题。此外,它还依赖于 Python3语义,其中“真除法”生成一个浮点数,而 CEIL ()函数返回一个整数。

简单的解决办法: A//b + 1

如果你想从一个数字中选择一个倍数,它的工作原理就像我们在 Excel 中使用 Math.celing 一样。

def excel_celling(number=None, multiple_off=None):
quotient = number // multiple_off
reminder = number % multiple_off
celling_value = quotient * multiple_off + (multiple_off, 0)[reminder==0]
return int(celling_value)




assert excel_celling(99.99, 100) == 100, "True"
print(excel_celling(99.99, 100) , 100)
assert excel_celling(1, 100) == 100, "True"
print(excel_celling(1, 100),100)
assert excel_celling(99, 100) == 100, "True"
print(excel_celling(99, 100),100)
assert excel_celling(90, 100) == 100, "True"
print(excel_celling(90, 100),100)
assert excel_celling(101, 100) == 200, "True"
print(excel_celling(101, 100),200)
assert excel_celling(199, 100) == 200, "True"
print(excel_celling(199, 100),200)
assert excel_celling(199.99, 100) == 200, "True"
print(excel_celling(199.99, 100),200)
assert excel_celling(200, 100) == 200, "True"
print(excel_celling(200, 100),200)

结果

100100

100100

100100

100100

200200

200200

200200

200200

您可以使用 -(-a//b)math.ceil(a/b)math的天花板划分。