【发布时间】:2021-04-25 06:50:49
【问题描述】:
有一个相对著名的技巧可以取消设置最右边的单个位:
y = x & (x - 1) // 0b001011100 & 0b001011011 = 0b001011000 :)
我发现自己有一个紧密的循环来清除最右边的 n 位,但是有没有更简单的代数技巧?
假设 n 相对较大(对于 64 位整数,n 必须
// x = 0b001011100 n=2
for (auto i=0; i<n; i++) x &= x - 1;
// x = 0b001010000
我翻阅了我的 TAOCP Vol4 几次,但找不到任何灵感。
也许有一些硬件支持?
【问题讨论】:
-
您关心任何特定的 ISA 以获得硬件支持?我认为 x86
pext/pdep可以使设置的位连续,以允许使用 AND 清除它们。 -
有趣 - 我简单地查看了
pext/pdep,但看来我需要提前计算掩码,对吧?我不能保证输入变量中的 n 位是连续的。 -
我还没有测试过这个,但我认为
pext(a,a)会在底部打包位:选择哪些位的所需掩码是输入数字,因为你想要所有的设置位而不是清除位。 -
随机想法:屏蔽掉一些任意数量的位(比如
(64+n)/2),使用popcount 来查看您清除了多少位,然后进行二分查找直到正确为止。最多应该进行 6 次迭代,但不可预测的分支可能会成为杀手,除非有聪明的无分支方法。 -
在支持
popcount但不支持pdep的硬件上,这是个好主意。我对@PeterCordes 的回答感到非常高兴(我自己)——它有效,而且一旦我阅读了 BMI2 手册,我实际上能够优化更多的地方;我仍然很好奇是否有办法在更受限制的硬件上加速它!在此期间,我会在几天内接受它。让我们征集非 BMI2 的替代品!
标签: bit-manipulation intrinsics integer-arithmetic