[英]Find the smallest power of 2 greater than or equal to n in Python
What is the simplest function to return the smallest power of 2 that is greater than or equal to a given non-negative integer in Python?在 Python 中返回大于或等于给定非负整数的最小 2 次幂的最简单函数是什么?
For example, the smallest power of 2 greater than or equal to 6 is 8.例如,大于或等于 6 的 2 的最小次方是 8。
Let's test it:让我们测试一下:
import collections
import math
import timeit
def power_bit_length(x):
return 2**(x-1).bit_length()
def shift_bit_length(x):
return 1<<(x-1).bit_length()
def power_log(x):
return 2**(math.ceil(math.log(x, 2)))
def test(f):
collections.deque((f(i) for i in range(1, 1000001)), maxlen=0)
def timetest(f):
print('{}: {}'.format(timeit.timeit(lambda: test(f), number=10),
f.__name__))
timetest(power_bit_length)
timetest(shift_bit_length)
timetest(power_log)
The reason I'm using range(1, 1000001)
instead of just range(1000000)
is that the power_log
version will fail on 0
.我使用range(1, 1000001)
而不是range(1000000)
的原因是power_log
版本将在0
上失败。 The reason I'm using a small number of reps over a largeish range instead of lots of reps over a small range is because I expect that different versions will have different performance over different domains.我在较大范围内使用少量代表而不是在小范围内使用大量代表的原因是因为我预计不同版本在不同领域会有不同的表现。 (If you expect to be calling this with huge thousand-bit numbers, of course, you want a test that uses those.) (如果您希望用巨大的千位数字调用它,当然,您需要一个使用这些数字的测试。)
With Apple Python 2.7.2:使用 Apple Python 2.7.2:
4.38817000389: power_bit_length
3.69475698471: shift_bit_length
7.91623902321: power_log
With Python.org Python 3.3.0:使用 Python.org Python 3.3.0:
6.566169916652143: power_bit_length
3.098236607853323: shift_bit_length
9.982460380066186: power_log
With pypy 1.9.0/2.7.2:使用 pypy 1.9.0/2.7.2:
2.8580930233: power_bit_length
2.49524712563: shift_bit_length
3.4371240139: power_log
I believe this demonstrates that the 2**
is the slow part here;我相信这表明2**
是这里缓慢的部分; using bit_length
instead of log
does speed things up, but using 1<<
instead of 2**
is more important.使用bit_length
而不是log
确实可以加快速度,但是使用1<<
而不是2**
更为重要。
Also, I think it's clearer.另外,我认为它更清楚。 The OP's version requires you to make a mental context-switch from logarithms to bits, and then back to exponents. OP 的版本要求您进行心理上下文切换,从对数切换到位,然后再切换回指数。 Either stay in bits the whole time ( shift_bit_length
), or stay in logs and exponents ( power_log
).要么一直保留在位中 ( shift_bit_length
),要么保留在对数和指数中 ( power_log
)。
Always returning 2**(x - 1).bit_length()
is incorrect because although it returns 1 for x=1, it returns a non-monotonic 2 for x=0.总是返回2**(x - 1).bit_length()
是不正确的,因为虽然它对 x=1 返回 1,但对 x=0 返回非单调的 2。 A simple fix that is monotonically safe for x=0 is:一个对 x=0 单调安全的简单修复是:
def next_power_of_2(x):
return 1 if x == 0 else 2**(x - 1).bit_length()
Sample outputs:示例输出:
>>> print(', '.join(f'{x}:{next_power_of_2(x)}' for x in range(10)))
0:1, 1:1, 2:2, 3:4, 4:4, 5:8, 6:8, 7:8, 8:8, 9:16
It can pedantically be argued that x=0 should return 0 (and not 1), since 2**float('-inf') == 0
.可以迂腐地争论说 x=0 应该返回 0(而不是 1),因为2**float('-inf') == 0
。
Would this work for you:这对你有用吗:
import math
def next_power_of_2(x):
return 1 if x == 0 else 2**math.ceil(math.log2(x))
Note that math.log2
is available in Python 3 but not in Python 2. Using it instead of math.log
avoids numerical problems with the latter at 2**29 and beyond.请注意, math.log2
在 Python 3 中可用,但在 Python 2 中不可用。使用它代替math.log
可避免后者在 2**29 及以后出现数值问题。
Sample outputs:示例输出:
>>> print(', '.join(f'{x}:{next_power_of_2(x)}' for x in range(10)))
0:1, 1:1, 2:2, 3:4, 4:4, 5:8, 6:8, 7:8, 8:8, 9:16
It can pedantically be argued that x=0 should return 0 (and not 1), since 2**float('-inf') == 0
.可以迂腐地争论说 x=0 应该返回 0(而不是 1),因为2**float('-inf') == 0
。
We can do this as follows using bit manipulation:我们可以使用位操作按如下方式执行此操作:
def next_power_of_2(n):
if n == 0:
return 1
if n & (n - 1) == 0:
return n
while n & (n - 1) > 0:
n &= (n - 1)
return n << 1
Sample outputs:示例输出:
>>> print(', '.join(f'{x}:{next_power_of_2(x)}' for x in range(10)))
0:1, 1:1, 2:2, 3:4, 4:4, 5:8, 6:8, 7:8, 8:8, 9:16
For further reading, refer to this resource .如需进一步阅读,请参阅此资源。
Hmm, I know this question is old and my answer is pretty simple, but I am really surprised in all this time nobody posted it here, so I will post it as an answer.嗯,我知道这个问题很老,我的回答也很简单,但我真的很惊讶这么久都没人把它贴在这里,所以我会把它作为答案贴出来。
The easiest solution is really simple, no need to import any library, you can do it in one loop if you use while
statement!最简单的解决方案真的很简单,不需要导入任何库,如果你使用while
语句,你可以在一个循环中完成!
So the logic is very simple, create a variable with a value of 1, while the value of the variable is less than the number, multiply the variable by 2!所以逻辑很简单,创建一个值为1的变量,当变量的值小于number时,将变量乘以2!
Code:代码:
i = 1
while i < n: i *=2
The return values for n = 1, 63, 64, 255, 256, 1000, 4095: n = 1、63、64、255、256、1000、4095 的返回值:
2, 64, 64, 256, 256, 1024, 4096
This can be easily modified to calculate the next power closet to a number of other bases as well:这可以很容易地修改以计算下一个到许多其他基地的电力壁橱:
def nextpower(num, base):
i = 1
while i < num: i *= base
return i
v+=(v==0);
v--;
v|=v>>1;
v|=v>>2;
v|=v>>4;
v|=v>>8;
v|=v>>16;
v++;
For a 16-bit integer.对于 16 位整数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.