下面代码实现了计算unsignedint X 这个数字中字节为1的个数,
int bit_count(unsigned int x )
{
static unsigned int mask[] = { 0x55555555,
0x33333333,
0x0F0F0F0F,
0x00FF00FF,
0x0000FFFF };
int i;
int shift; /* number of positions to shift to right */
for( i=0, shift=1; i < 5; i++, shift *= 2 )
x = (x & mask[i]) + ( (x >> shift) & mask[i] );
return x;
}
那么则么去
理解这个问题呢?为什么它可以计算出一个unsigned int 中字节为1的个数?
通过自己查阅终于知道了这个是计数器合并问题。
它是通过加数据的0位和1位。最终得到的总数就等于在这个数据中1的位数。
其中mask[0]= 0x55555555 = 01010101 01010101 01010101 01010101(01间隔)
mask[1]= 0x33333333 = 00110011 00110011 00110011 00110011(01间隔2位)
mask[2]= 0x0F0F0F0F = 00001111 00001111 00001111 00001111(01间隔4位)
mask[3]= 0x00FF00FF = 00000000 11111111 00000000 11111111(01间隔8位)
B[4]= 0x0000FFFF = 00000000 00000000 11111111 11111111 (01间隔16位)
其中把输入数的32Bit(unsigned int)当作32个计数器,代表每一位的1个数。然后合并相邻的2个“计数器”,使i成为16个计数器,每个计数器的值就是这2个Bit的1的个数;继续合并相邻的2个“计数器“,使i成为8个计数器,每个计数器的值就是4个Bit的1的个数。。依次类推,直到将i变成一个计数器,那么它的值就是32Bit的i中值为1的Bit的个数。
举例说明,简单来说一个data数据为10110011(二进制),十六进制常量0x55的二进制表示为01010101(有效数据只有8位,前面补0,不考虑)。在这个加法的第一个操作数中,data与这个常量进行了AND运算,奇数的位就被拿出来了。第二操作数((data>> 1) &0x55),首先移动所有的偶数位到奇数位上,然后使用相同的掩码得到这些相同的位。现在,第一个操作数含有data的奇数位而第二个操作数含有偶数位。把这两个操作数相加就相当于把data的奇数位和偶数位相加,这个字节的位被分成了四个2位的字段来展示实际上执行了四个独立的加法。当然,总的位数还没被计算出来。但是,可以使用跟上面一样的技术,经过同样的步骤来计算总数。最终得到一个数字便是字节为1的个数。
这样便可以算出其中为1的个数了。