【发布时间】:2015-06-02 01:43:53
【问题描述】:
popcount 函数返回输入中 1 的数量。 0010 1101 的 popcount 为 4。
目前,我正在使用这个算法来获取popcount:
private int PopCount(int x)
{
x = x - ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
这很好用,我要求更多的唯一原因是因为这个操作非常频繁地运行,我正在寻找额外的性能提升。
我正在寻找一种方法来简化算法,因为我的 1 将始终正确对齐。也就是说,输入将类似于 00000 11111(返回 5)或 00000 11111 11111(返回 10)。
有没有一种方法可以根据这个约束来进行更有效的 popcount?如果输入是01011 11101 10011,它只会返回 2,因为它只关心最右边的那些。似乎任何一种循环都比现有解决方案慢。
【问题讨论】:
-
换句话说,您是在问“计数前导零”(clz)操作是否比“计数全1”(popcnt)更快?
-
您可以将其计算为
trailing_zeroes(~x),这在 x86 汇编中会很好,但在 C# 中仍然很烦人。您可以尝试使用“双重黑客”,但我不期待太多.. -
@harold: 或者
lg2(x+1)有一些快速的二进制对数技巧。 -
~x的尾随零计数看起来很有希望。我会尝试对差异进行基准测试,看看哪个更可取。
标签: c# algorithm binary bit-manipulation hammingweight