簡體   English   中英

在 Python 中找到大於或等於 n 的最小 2 次方

[英]Find the smallest power of 2 greater than or equal to n in Python

在 Python 中返回大於或等於給定非負整數的最小 2 次冪的最簡單函數是什么?

例如,大於或等於 6 的 2 的最小次方是 8。

讓我們測試一下:

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)

我使用range(1, 1000001)而不是range(1000000)的原因是power_log版本將在0上失敗。 我在較大范圍內使用少量代表而不是在小范圍內使用大量代表的原因是因為我預計不同版本在不同領域會有不同的表現。 (如果您希望用巨大的千位數字調用它,當然,您需要一個使用這些數字的測試。)

使用 Apple Python 2.7.2:

4.38817000389: power_bit_length
3.69475698471: shift_bit_length
7.91623902321: power_log

使用 Python.org Python 3.3.0:

6.566169916652143: power_bit_length
3.098236607853323: shift_bit_length
9.982460380066186: power_log

使用 pypy 1.9.0/2.7.2:

2.8580930233: power_bit_length
2.49524712563: shift_bit_length
3.4371240139: power_log

我相信這表明2**是這里緩慢的部分; 使用bit_length而不是log確實可以加快速度,但是使用1<<而不是2**更為重要。

另外,我認為它更清楚。 OP 的版本要求您進行心理上下文切換,從對數切換到位,然后再切換回指數。 要么一直保留在位中 ( shift_bit_length ),要么保留在對數和指數中 ( power_log )。

總是返回2**(x - 1).bit_length()是不正確的,因為雖然它對 x=1 返回 1,但對 x=0 返回非單調的 2。 一個對 x=0 單調安全的簡單修復是:

def next_power_of_2(x):  
    return 1 if x == 0 else 2**(x - 1).bit_length()

示例輸出:

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

可以迂腐地爭論說 x=0 應該返回 0(而不是 1),因為2**float('-inf') == 0

這對你有用嗎:

import math

def next_power_of_2(x):
    return 1 if x == 0 else 2**math.ceil(math.log2(x))

請注意, math.log2在 Python 3 中可用,但在 Python 2 中不可用。使用它代替math.log可避免后者在 2**29 及以后出現數值問題。

示例輸出:

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

可以迂腐地爭論說 x=0 應該返回 0(而不是 1),因為2**float('-inf') == 0

我們可以使用位操作按如下方式執行此操作:

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

示例輸出:

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

如需進一步閱讀,請參閱此資源

嗯,我知道這個問題很老,我的回答也很簡單,但我真的很驚訝這么久都沒人把它貼在這里,所以我會把它作為答案貼出來。

最簡單的解決方案真的很簡單,不需要導入任何庫,如果你使用while語句,你可以在一個循環中完成!

所以邏輯很簡單,創建一個值為1的變量,當變量的值小於number時,將變量乘以2!

代碼:

i = 1
while i < n: i *=2

n = 1、63、64、255、256、1000、4095 的返回值:

2, 64, 64, 256, 256, 1024, 4096

這可以很容易地修改以計算下一個到許多其他基地的電力壁櫥:

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

對於 16 位整數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM