Python中是否有一个//运算符的上限?


127

我发现了//Python中的运算符,在Python 3中该运算符与下限相除。

是否有一个运算符与ceil分开?(我知道/在Python 3中执行浮点除法的运算符。)


1
重要提示:您想要整数或浮点结果吗?
smci 2015年

10
您应该将接受的答案更改为dlitz。math.ceil用于浮点数,不适用于Python的任意精度长整数。
Endlith '16

2
@milllimoose这个问题是正确的,因为1)“天花板除法”也是基于“模除法”,2)数学并没有真正说出什么是共同点,什么不是,3)您需要对“连续仓位”进行此操作包装问题”,即需要包装多少盒$ k $。
Tomasz Gandor

Answers:


55

没有运算符与ceil分开。您需要import math使用math.ceil


所以foobar = math.ceil(foo / bar)?嗯,我可以忍受,不知道我想使用它的任何地方,只是好奇,谢谢
Cradam 13'Feb 11'13

37
–1 不要使用,对于很大的整数,这将开始失败。使用多精度算术库,或者使用这种方法都位于整数域中。
WIM

5
绝对留在整数域中。几乎可以保证它具有更高的性能,并且减少了头痛。
Samy Bencherif

1
@David天宇Wong gmpy2(在另一个答案中提到)很好。
WIM

1
请注意math.ceil限制为53位精度。如果使用大整数,则可能无法获得准确的结果。
techkuz

290

您可以做上下颠倒的楼层划分:

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

之所以有效,是因为Python的除法运算符执行地板除法(与C语言不同,整数除法会截断小数部分)。

这也适用于Python的大整数,因为没有(有损的)浮点转换。

这是一个示范:

>>> from __future__ import division   # a/b is float division
>>> from math import ceil
>>> b = 3
>>> for a in range(-7, 8):
...     print(["%d/%d" % (a, b), int(ceil(a / b)), -(-a // b)])
... 
['-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]

2
@apadana我同意这是非常聪明的做法,但不是很易读且难以维护!我决定从数学中导入ceil,以便当我的一位同事阅读我的代码行时,他将明白它的作用!
SlimCheney

2
@apadana我不同意。该问题询问是否“在” Python中“存在”该操作符。根据回答,答案似乎是“否”。不过,我赞成dlitz的回答。
安娜·尼姆布斯

11
@SlimCheney将此方法转换为已记录的函数,您可以开始使用。一次扫动的性能和可读性。
Samy Bencherif

2
@SamyBencherif:不仅是性能+可读性,还包括大输入的正确性;浮点数具有表示法上的限制,而Python int则没有(限制,没有意义;在64位Python上,您只能使用30 * (2**63 - 1)位数),甚至临时转换为float也会丢失信息。比较math.ceil((1 << 128) / 10)-(-(1 << 128) // 10)
ShadowRanger

1
它应该只包含在标准库中
endolith

26

你可以做(x + (d-1)) // d划分时x通过d,即(x + 4) // 5


2
这是我永远使用的经典方法。但是不适用于负除数。
Mark Ransom

它产生了相同的结果作为math.ceil()
阿披耶特(Abhijeet)

3
@Abhijeet是的,这就是问题所在。除非它对上面的大整数更好sys.float_info.max,并且不需要导入。
Artyer

21

解决方案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)

所述divmod()函数给出(a // b, a % b)为整数(这可能是用浮漂较不可靠,由于舍入误差)。bool(r)每当存在非零余数时,带有的步骤会将商加1。

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

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

向上平移分子,以便将地板划分向下舍入到所需的上限。注意,这仅适用于整数。

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

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

math.ceil()代码很容易理解,但它从整数到彩车和背部转换。这不是很快,并且可能存在舍入问题。而且,它依赖于Python 3语义,其中“真除法”产生浮点,而ceil()函数返回整数。


2
在快速测试中,#1是最快的,即使与-(-a // b)o_O 相比也是如此
endolith

至少在与-(a // -b)-(-a // b)python -m timeit ...
Jasha

19

您也可以随时内联进行

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

在python3中,只要您关心速度,这比强制进行float除法和调用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

我自己进行了这些测试,我得到了大约12.5秒,嗯,为什么速度差如此之大,我为什么不关心速度?
Cradam

3
@Cradam请注意,他正在使用1亿个电话(number=100000000)。每次通话,差异很小。
Rushy Panchal 2013年

4
因为代码的清晰性胜过一切。在这种情况下,明确性可能是客观的。但是,您应该始终使可读/可维护。当且仅当您发现性能检查点时,您才能违反规则。现代机器是如此之快,因此您的程序正在执行的所有其他操作常常会在噪声中消除这种差异。
特拉维斯·格里格斯

6
@TravisGriggs使用整数数学而不是浮点数学并不只是为了提高速度。对于足够大的整数,浮点数学给出了错误的答案
Endolith '23

1
例如,如果foo = -8bar = -4,则答案应为2,而不是3 -8 // -4。Python底数划分被定义为“对结果应用'floor'函数的数学除法”,而顶数划分是相同的,但用ceil()代替floor()
endolith

8

请注意math.ceil限制为53位精度。如果使用大整数,则可能无法获得准确的结果。

gmpy2 libary提供c_div它采用天花板的舍入函数。

免责声明:我维护gmpy2。


3
如果我在做大量以数学或科学为导向的事情,那么此软件包将很有用,尽管我更喜欢使用核心库的答案。我正在投票,尽管它是一个有用的答案
Cradam

哇,可以确认。python2 -c 'from math import ceil;assert ceil(11520000000000000102.9)==11520000000000000000'(以及替代python3)都是True
JamesTheAwesomeDude

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.