【发布时间】:2020-01-27 22:42:43
【问题描述】:
我想在 Python 中实现 64 位 popcount 的小技巧。我尝试复制this code如下:
def popcount_test(y):
y -= ((y >> 1) & 0x5555555555555555)
y = (y & 0x3333333333333333) + (y >> 2 & 0x3333333333333333)
return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0f) * 0x101010101010101 >> 56
不幸的是,这是不对的。我们可以通过对 int 1234 执行 popcount 来看到这一点。
popcount_test(1234)
261
bin(1234).count('1')
5
在 Python 中正确的位技巧是什么?
可以通过以下方式进行进一步测试:
import random
num = random.randint(0, 2**64-1)
print(popcount_test(num), bin(num).count('1'))
【问题讨论】:
-
与类似的 C 代码最明显的区别是 Python 中的整数乘法是“无限精度”,但 C 代码只保留了乘积的最低有效 64 位。因此,首先,尝试通过
&屏蔽产品,并使用0xffffffffffffffff对其进行屏蔽。 -
@TimPeters 对。或者
&和0xff在>> 56之后(很容易看到它会修复所示情况)。 -
我可以确认上述两个修复都有效(我测试了与@HeapOverflow 建议的相同的东西,但之前的一项操作 Tim Peters 会做同样的事情)。
-
在实践中,我也会先转换
&和0xff。不过,我给出的答案是让它尽可能地无意识地模仿 C 代码的实际作用;-)