位计数
位计数(Counting bits set),指的是计算一个数里bit位置1的个数,例如一个8位数0xea = 0b1110 1010,位置1的个数为5。
算法说明
该算法每次清除从最低位到最高位数的第一个为1的位,运算次数取决于二进制位中1的个数。
位计数算法代码
32位数的位计数代码
unsigned int count(unsigned int v)
{
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
v &= v - 1; // clear the least significant bit set
}
return c;
}
8位数的位计数代码
unsigned char count(unsigned char v)
{
unsigned char c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
v &= v - 1; // clear the least significant bit set
}
return c;
}
算法来源
1988年,发布于《C程序设计语言》(第二版),作者Brian W. Kernighan和Dennis M. Ritchie。在此书的练习2-9中提到了这个算法。
Bit Twiddling Hacks
算法计算过程
算法核心在于v &= v - 1这句代码。v &= v - 1 => v = v & (v - 1),v & (v - 1)用于清除掉从最低位到最高位数的第一个为1的位,循环中每次都能清除一个位,根据清除位的次数,就可以知道数里bit位置1的个数。
例如一个数为0b0110 1000
v : v = 0b0110 1000
c : c = 0
v : v > 0
v &= v - 1
0b0110 1000
& 0b0110 0111
---------------
0b0110 0000
v : v = 0b0110 0000
c++ : c = 1
v : v > 0
v &= v - 1
0b0110 0000
& 0b0101 1111
---------------
0b0100 0000
v : v = 0b0100 0000
c++ : c = 2
v : v > 0
v &= v - 1
0b0100 0000
& 0b0011 1111
---------------
0b0000 0000
v : v = 0b0000 0000
c++ : c = 3
v : v = 0
最后得到结果,0b0110 1000这个数位置1的个数为3。
[参考资料]
Bit Twiddling Hacks By Sean Eron Anderson
[Hacker’s Delight] 作者: Henry S. Warren Jr.