位计数
位计数(Counting bits set),指的是计算一个数里bit位置1的个数,例如一个8位数0xea = 0b1110 1010,位置1的个数为5。
算法说明
该算法用于计算最大为24位的数。这个算法需要在支持快速模除的64位CPU上才能达到高性能的效果。计算24位数的位置1的个数,只需要10次操作。
位计数代码
位计数代码
unsigned int count_24bit(unsigned int x)
{
unsigned int val;
val = ((x & 0xfff) * 0x1001001001001ULL & 0x84210842108421ULL) % 0x1f;
val += (((x & 0xfff000) >> 12) * 0x1001001001001ULL & 0x84210842108421ULL)
% 0x1f;
return val;
}
算法来源
算法计算过程
用abcd efgh ijkl mnop qrst uvwx表示一个24bit数的24个bit位。
一共只需要10次操作。
1.x & 0xfff
x与0xfff, 得到低12bit。
2.(x & 0xfff) * 0x1001001001001ULL
步骤一得到的数值再乘0x1001001001001ULL。
3.(x & 0xfff) * 0x1001001001001ULL & 0x84210842108421ULL
步骤二得到的数值再与0x84210842108421ULL。
4.((x & 0xfff) * 0x1001001001001ULL & 0x84210842108421ULL) % 0x1f
步骤三得到的数值再取模运算0x1f,就是31,31 =
2
5
−
1
2^{5} - 1
25−1 ,相当于将每5bit的数合并在一起,从0-4,5-9,10-14,15-19,……。
5.x & 0xfff000
x与0xfff,得到高12bit。
6.(x & 0xfff000) >> 12
步骤一得到的数值右移12位。
7.((x & 0xfff000) >> 12) * 0x1001001001001ULL
步骤六得到的数值再乘0x1001001001001ULL。
8.((x & 0xfff000) >> 12) * 0x1001001001001ULL & 0x84210842108421ULL
步骤七得到的数值再与0x84210842108421ULL。
9.(((x & 0xfff000) >> 12) * 0x1001001001001ULL & 0x84210842108421ULL) % 0x1f
步骤八得到的数值再取模运算0x1f,就是31,31 =
2
5
−
1
2^{5} - 1
25−1 ,相当于将每5bit的数合并在一起,从0-4,5-9,10-14,15-19,……。
10.步骤4和步骤9得到的值相加
val =(x+s+n+u+p+w+r+m+t+o+v+q) + (l+g+b+i+d+k+f+a+h+c+j+e)
最后得到结果,就是把每个bit的值相加,得到的数值就是数里bit位置1的个数。
[参考资料]
Bit Twiddling Hacks By Sean Eron Anderson
[Hacker’s Delight] 作者: Henry S. Warren Jr.