范围似乎是已知的。让我们假设它上升到 1<<20,只是为了让它更有趣:
max_log2=20
所以制作一个列表,(实际上)将一个整数映射到它的以 2 为底的对数。以下将解决问题:
log2s_table=[0]*((1<<max_log2)+1)
for i in range(max_log2+1):
log2s_table[1<<i]=i
(这对于不是 2 的幂的数字没有任何用处;问题陈述表明它们不需要处理。不过很容易解决这个问题。)
获取对数的函数非常简单,可以很容易地内联:
def table(v):
return log2s_table[v]
我不能保证我编写的测试代码与用于获取示例计时的代码完全相同,但这比stringcount
代码要快得多:
stringcount: 0.43 s.
table: 0.16 s.
由于表中的所有值都小于 256,我想知道使用字符串而不是列表是否会更快,或者可能是一个array.array
字节,但没有骰子:
string: 0.25 s.
arr: 0.21 s.
使用 adict
进行查找是另一种可能性,利用仅检查两个幂的方式:
log2s_map=dict([(1<<x,x) for x in range(max_log2+1)])
def map(v):
return log2s_map[v]
但是,结果并不那么好:
map: 0.20 s.
只是为了好玩,人们还可以hex
在浮点对象上使用该方法来获取一个字符串,该字符串包括(作为其最后一部分)该数字的以 2 为底的指数。一般来说,这有点慢,但如果指数只是一位数,它可以很简单地完成:
def floathex(v):
return ord(float(v).hex()[-1])-48
这纯粹是为了娱乐价值,因为它没有竞争力——但令人惊讶的是,它仍然比按位方法更快。
所以看起来使用列表是要走的路。
(由于内存有限,这种方法不会无限扩展,但为了弥补这一点,执行速度不会以max_log2
运行 python 代码时会注意到的任何方式依赖于 或输入值。关于内存消费,如果我没记错我的python内部,表格将占用大约(1<<max_log2)*4
字节,因为内容都是解释器会自动实习的小整数。所以,当max_log2
是20时,大约是4MB。)