位计数
位计数(Counting bits set),指的是计算一个数里bit位置1的个数,例如一个8位数0xea = 0b1110 1010,位置1的个数为5。
算法说明
该算法是基于分治法(divide and conquer)的优化算法,分治法是指以两个相邻的bit位为一组,将这两个bit的数值相加,得到的结果放到大小为2bit的位段空间里。然后再将相邻的两个2bit位段数值相加,得到的结果放到4bit的位段空间里,以此类推,最终完成位计数。分治法可以参照位计数算法 分治法统计。优化原理可以参照[Hacker’s Delight],中文版叫算法心得-高效算法的奥秘。
位计数代码
32位数的位计数代码
unsigned int count(unsigned int x)
{
x = x - ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
x = (x + (x >> 4)) & 0x0f0f0f0f;
x = x + (x >> 8);
x = x + (x >> 16);
return x & 0x0000003f;
}
算法来源
[Hacker’s Delight] 作者: Henry S. Warren Jr.
算法计算过程
演示一个32位数的位计数过程。
假设数值为0xB90D8B1B = 0b10111001000011011000101100011011
第一步:
原本的分治法代码
x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
被优化为
x = x - ((x >> 1) & 0x55555555);
优化后,该行代码计算过程如下:
x的值为:
((x >> 1) & 0x55555555)的值为:
相减得到:
第二步:
第一步得到的数值:
将相邻的两个2bit位段数值相加,得到的结果放到4bit的位段空间里。
得到如下结果:
第三步:
第二步得到的数值:
第三步的代码
原本的分治法代码
x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f);
被优化为
x = (x + (x >> 4)) & 0x0f0f0f0f;
其中x >> 4
得到
(x + (x >> 4))
得到
与上0x0f0f0f0f
得到:
第四步:
第三步得到结果:
(x >> 8)
得到
x = x + (x >> 8);
得到
第五步:
第四步得到的结果:
(x >> 16)
得到
x = x + (x >> 16);
得到
第六步:
x & 0x0000003f
得到:
最后得到数里bit位置1的个数为16。
[参考资料]
[Hacker’s Delight] 作者: Henry S. Warren Jr.