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)