统计二进制中1的个数

来源:互联网 发布:复旦管院 知乎 编辑:程序博客网 时间:2024/05/17 22:57

题目:统计一个无符号数中的二进制表示中1的个数。

此算法名为平行计算法。基本思想如下:

先两两(两个二进制位)分组统计每组出现的1的个数,而每组1的个数只可能是0个(00),1个(01)或2个(10),由(相加所得的)两位的二进制完全可以表示每组(两个二进制数)中1的个数;接着四四(4个二进制位)的分组,每组内有两个分别用两位二进制数表示的数字,而这些两位二进制数字又是上一步得来的表示1的个数的,因此在每组内把每两位二进制数当作一个整体的数字来相加,就可以看出四四分组的每四个二进制里面有多少个1;以此类推......

下面这张图很直观(来源于网络)

统计二进制中1的个数

但是图片不足以说明我们求解的逻辑过程:例a=1001011101111101(16-bits)

1.两两分组,求每组的1的个数

   1 0 0 1 0 1 1 0=01 00 00 0100 01 01 00

+ 0 1 1 1 1 1 1 1=00 01 01 01 01 01 01 01

——————————————————————

   1 1 1 21 2 2 1=01 01 01 10 01 10 10 01

注意:上下两个二进制数才是一组,这样才能实现组内相加, 相加的结果用两位二进制来表示。

那么怎样用语言来实现呢?

肯定是两个二进制数相加来表示的,下面那个只留了8-bits的偶数位,只需把其与0101010101010101相与即可,即1001011101111101&0101010101010101(0x5555)=0001010101010101(01111111),另一个是只留了奇数位,1001011101111101&1010101010101010(0xAAAA)=1000001000101000,得到的这个位模式不能与上面的那个偶数位直接相加(那不等于原来的数了么),因为它是向右偏移了一位的(实质上对于原数而言,应该是第1位与第0位相加,第3位与第2位相加...第15位与第14位相加),很显然,把我们得到的结果右移1位变为0100000100010100即可。

综上,两两分组组内相加的最终表示就是(a&0x5555)+((a&0xAAAA)>>1);

2.四四分组,组内相加,求1的个数(原数变为0101 0110 0110 1001)

    01 10 1001=0001 0010 0010 0001

01 01 01 10=0001 0001 0001 0010

——————————————————

    10 11 1111=0010 0011 0011 0011

怎样由0101 0110 0110 1001变为0001 0010 00100001(只保留每组的低两位),原数与0x3333相与即可,

怎样由0101 0110 0110 1001变为0001 0001 00010010(只保留每组的高两位),原数与0xCCCC相与是不够的,同样存在1中的问题,把相与的结果右移两位即可.

3.......

 

其实,问题的核心在于如何把每组的高位和低位剥离,实现组内相加,总结起来就一句话,用的着的位用1相与保留,不用的与0相与置0,组内的空位(在高位)用0补齐(16位),最后,不要忘了移位!

统计二进制中1的个数统计二进制中1的个数

 

参考资料:http://everything2.com/title/Counting+1+bits

                http://blog.csdn.net/morewindows/article/details/7354571

0 0
原创粉丝点击