計數位設定
在密碼學和其他應用中經常需要位元串的人口數,並且該問題已被廣泛研究。
天真的方式需要每位迭代一次:
unsigned value = 1234;
unsigned bits = 0; // accumulates the total number of bits set in `n`
for (bits = 0; value; value >>= 1)
bits += value & 1;
一個很好的技巧(基於刪除最右邊的設定位 )是:
unsigned bits = 0; // accumulates the total number of bits set in `n`
for (; value; ++bits)
value &= value - 1;
它經歷了與設定位一樣多的迭代,因此當 value
預期具有很少的非零位時,這是好的。
該方法最初是由 Peter Wegner 提出的(在 CACM 3/322 - 1960 中),因為它出現在 *C 程式語言中,*由 Brian W. Kernighan 和 Dennis M. Ritchie 提出。
這需要 12 次算術運算,其中一次是多次運算:
unsigned popcount(std::uint64_t x)
{
const std::uint64_t m1 = 0x5555555555555555; // binary: 0101...
const std::uint64_t m2 = 0x3333333333333333; // binary: 00110011..
const std::uint64_t m4 = 0x0f0f0f0f0f0f0f0f; // binary: 0000111100001111
x -= (x >> 1) & m1; // put count of each 2 bits into those 2 bits
x = (x & m2) + ((x >> 2) & m2); // put count of each 4 bits into those 4 bits
x = (x + (x >> 4)) & m4; // put count of each 8 bits into those 8 bits
return (x * h01) >> 56; // left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
}
這種實現具有最好的最壞情況行為( 有關詳細資訊,請參閱漢明重量 )。
許多 CPU 都有特定的指令(如 x86 的 popcnt
),編譯器可以提供特定的( 非標準 )內建函式。例如,使用 g ++有:
int __builtin_popcount (unsigned x);