我们来测试一下: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上失败。我之所以在一个大范围内使用少量的rep,而不是在一个小范围内使用大量的rep,是因为我希望不同的版本在不同的域上有不同的性能。(当然,如果您希望使用大量的千位数字来调用它,那么您需要一个使用这些数字的测试。)
使用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)。