算法 - 求二进制数中1的个数
转自 : https://www.cnblogs.com/graphics/archive/2010/06/21/1752421.html
一些简单的方法就不转了,转最后两个
平行算法
int BitCount4(unsigned int n) { n = (n &0x55555555) + ((n >>1) &0x55555555) ; n = (n &0x33333333) + ((n >>2) &0x33333333) ; n = (n &0x0f0f0f0f) + ((n >>4) &0x0f0f0f0f) ; n = (n &0x00ff00ff) + ((n >>8) &0x00ff00ff) ; n = (n &0x0000ffff) + ((n >>16) &0x0000ffff) ; return n ; }
算法原理:
先将n写成二进制形式,然后相邻位相加,重复这个过程,直到只剩下一位。
以217(11011001)为例,有图有真相,下面的图足以说明一切了。217的二进制表示中有5个1
图中第一行,是数据 217的 二进制表现形式
图中第二行,是先按两两分组,然后再相加,即
n = (n &0x55555555) + ((n >>1) &0x55555555)
其中第二个与操作,是为了清除移位操作时,高位分组侵入到低位分组的数据:
1 1 0 1 1 0 0 1
1 1 0 1 1 0 0 1
---------------------------------
10 01 01 01
黄色部分被 "与" 操作清除,剩余部分相加,
然后继续分组,4 bit 一组 :
n = (n &0x33333333) + ((n >>2) &0x33333333) ;
10 01 01 01
10 01 01 01
----------------------------------
0011 0010
最后,8 bit 一组:
n = (n &0x0f0f0f0f) + ((n >>4) &0x0f0f0f0f) ;
0011 0010
0011 0010
-----------------------------------
0101
即最后结果,
此例为8 bit, 如果是 16 bit 或则 32 bit,则继续执行 一到两次分组即可。
完美法
int BitCount5(unsigned int n) { unsigned int tmp = n - ((n >>1) &033333333333) - ((n >>2) &011111111111); return ((tmp + (tmp >>3)) &030707070707) %63; }
这是 8进制计算, 其中 十进制数63换算为8进制是 077,这里我准备分析十六进制的原理,8进制和十六进制是一样的。
#define BITCOUNT(x) (((BX_(x)+(BX_(x)>>4)) & 0x0F0F0F0F) % 255) #define BX_(x) ((x) - (((x)>>1)&0x77777777) - (((x)>>2)&0x33333333) - (((x)>>3)&0x11111111))
32位的十六进制数,按4 bit 一组进行分组,对任意的 4bit 数 x, 都可以写成如下形式:
x = 2^3 * a + 2^2 * b + 2^1 * c + d
其中 a,b, c, d取值 0或者 1 ,也就是典型的8421 十六进制表达。于是 a+b+c+d的值,就是当前分组的1的个数。
展开来就是:
x = 8a + 4b + 2c + d
十六进制的右移操作,也可以理解为除 2 操作,
而 与操作,则是清除移位时,高位分组的低位 侵入到 低位分组的高位 数据
ex : 1010 1100 >> 1 = x101 0110
红色数据是侵入数据,可以通过 与操作清除
将 BX_(x) 展开,就是:
(8a+4b+2c+d) - (8a+4b+2c+d) /2 - (8a+4b+2c+d) /4 - (8a+4b+2c+d) /8
= (8a+4b+2c+d) - (4a+2b+c) - (2a+b) - (a)
= a+b+c+d
可见,结果就是求出了各个分组的1的个数。
下一步操作就是累加每个分组中 1的个数,与平行算法类似,错位相加,得到8bit中1的个数,由于与操作,所以结果的形式如下:
BITCOUNT(x) = 0x0a0b0c0d
余除 255后,就是1的累加值,怎么来的?
先把值展开 :
d + c * 256 + b * 256^2 + a * 256 ^3
= d + c* (255+1) + b * (255+1)^2 + a * (255+1)^3
对每一项余除 255,
d % 255 = d
c * (255+1) % 255 = c * 255 %255 + c %255 = 0 + c
另外, X *(255+1)^n 根据数学原理,展开后,除最后一项是1外,其他的项都是 255的倍数,255倍数余除 255,结果为0, 所以只会保留 X %255,也就是 X的值。
所以,[ d + c* (255+1) + b * (255+1)^2 + a * (255+1)^3 ] %255 = d + c + b + a, 也就是累加了每一组中 1的个数。