1. 目标:计算32位整形数内含有1的个数
2. 最原本的思想:将整形数对应的32位二进制数字中所有的1加起来就是所求的结果。
即:
7=0000-0000-0000-0000-0000-0000-0000-0111=0+0+…+0+1+1+1=3
3. 简化后的思想:逐次将相邻位的1相加,最后得到的总数就是要求的结果。
a) 7=0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-1-1-1
=>7=00-00-00-00-00-00-00-00-00-00-00-00-00-00-01-10
注释:相邻2位相加,实际上是1位加1位,得到相邻2位1的总和,为了防止得到的值溢出,在保证和不变的同时,将1位加1位的和用2位表示,仍然放在原来的位置上,不过此时,相邻2位表示的是一个值,应看作一个整体。
b) 7=00-00-00-00-00-00-00-00-00-00-00-00-00-00-01-10
=>7=0000-0000-0000-0000-0000-0000-0000-0011
注释:相邻4位相加(相邻2个值相加),实际上还是1个值加1个值,得到相邻
4位1的总和,为了防止溢出,将1个值(2位)加1个值(2位)的和变为4位,仍然放在原来的位置上,不过此时相邻4位看作一个值,表示原来相邻4位中1的总和,应看作一个整体。
c) 7=0000-0000-0000-0000-0000-0000-0000-0011
=>7=00000000-00000000-00000000-00000011
注释:依次类推,相邻8位在原来4位的基础上相加,得到相邻8位1的总和,放在原来的位置上,不过此时相邻8位看作一个值,表示原来8位中1的总和,应看作一个整体参与下一次的运算中。
d) 7=00000000-00000000-00000000-00000011
=>7=0000000000000000-0000000000000011
注释:依次类推,相邻16位在原来8位的基础上相加,得到相邻16位1的总和,放在原来的位置上,不过此时相邻16位看作一个值,表示原来16位中1的总和,应看作一个整体参与下一次的运算中。
e) 7=0000000000000000-0000000000000011
=>7=00000000000000000000000000000011
注释:依次类推,相邻32位在原来16位的基础上相加,得到相邻32位1的总和,放在原来的位置上,不过此时相邻32位看作一个值,表示原来32位中1的总和,应看作一个整体参与下一次的运算中。
4. 利用掩码实现简化后的思想。
代码实现如下:
intCountBits(unsigned int x)
{
static unsigned int mask[] =
{
0x55555555,
0x33333333,
0x0f0f0f0f,
0x00ff00ff,
0x0000ffff
};
int i; //计算循环次数以及取正确的掩码值
int shift;/*Number of positions to shift toright*///计算正确的右移位数,右移位数用于将高位移动到对应低位
for(i = 0, shift = 1; i< 5; i++,shift *= 2)
{
printf("i = %d shift = %d mask[i] = %d x=%d x>>shift = %d x= %d\n",i,shift,mask[i],x,x>>shift,
(x & mask[i]) + ((x >>shift) & mask[i]));
x = (x & mask[i]) + ((x >>shift) & mask[i]);
}
return x;
}
代码分析:
a) i//计算循环次数以及取正确的掩码值
shift//计算正确的右移位数,右移位数用于将高位移动到对应低位
循环0-4对应3中思想分析的a-e
取x = 7;
当i = 0,shift = 1 时,
x = 7=0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-1-1-1,
mask[0]=0x55555555=0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1-0-1
分析x = (x & mask[i]) + ((x >> shift) & mask[i]);
x & mask[0]将相邻2位中的高位全部置0,而低位的有效位全部保留了下来。
x>>shift将x所有位右移一位,即将相邻2位中的高位全部移动到了低位的位置上,同时保证了高位的有效位没有损失。
(x>>shift)&mask[0]将移动后的低位,即原来相邻2位中的高位有效位全部保留下来了。
x = (x &mask[i]) + ((x >> shift) & mask[i]);实现了相邻2位依次相加,并将值保留至原来相邻2位上的功能。
对应于3.a)
b) 当 i=1,shift = 1*2时,
x=7=00-00-00-00-00-00-00-00-00-00-00-00-00-00-01-10
mask[1]=0x33333333=00-11-00-11-00-11-00-11-00-11-00-11-00-11-00-11
分析x = (x & mask[i]) + ((x >> shift) & mask[i]);
与4.a)类似,实现了相邻4位依次相加,并将值保留至原来相邻4位上的功能。
对应于3.b)
c) 当i=2, shift = 1*2*2时,
x=7=0000-0000-0000-0000-0000-0000-0000-0011
mask[2]=0x0f0f0f0f=0000-1111-0000-1111-0000-1111-0000-1111
分析x = (x & mask[i]) + ((x >> shift) & mask[i]);
与4.c)类似,实现了相邻8位依次相加,并将值保留至原来相邻8位上的功能。
对应于3.c)
d) 当i=3, shift = 1*2*2*2时,
x=7=00000000-00000000-00000000-00000011
mask[2]=0x00ff00ff=00000000-11111111-00000000-11111111
分析x = (x & mask[i]) + ((x >> shift) & mask[i]);
与4.d)类似,实现了相邻16位依次相加,并将值保留至原来相邻16位上的功能。
对应于3.d)
e) 当i=4, shift = 1*2*2*2*2时,
x=7=0000000000000000-0000000000000011
mask[2]=0x0000ffff=0000000000000000-1111111111111111
分析x = (x & mask[i]) + ((x >> shift) & mask[i]);
与4.e)类似,实现了相邻32位依次相加,并将值保留至原来相32位上的功能。
对应于3.e)