统计32位二进制数中有多少个1

一、关于关于数字位数线性

for(n=0; b; b >>= 1) if (b & 1) n++;

二、关于"1"的个数线性

for(n=0; b; n++) b &= b-1;

三、最神级的方法

m = m - ((m>>1)&(033333333333)) - ((m>>2)&(011111111111));

n= ( (m + (m>>3)) & (030707070707) )   %(63);

下面解释这代码的含义:

对于第一行,先看3位二进制,如:5=101,我们把它表示成 abc,那么1的个数就是a+b+c

5=4a+2b+c;

(5>>1)&(03)=2a+b;

(5>>2)&(01)=a;

所以 5-(5>>1)&(03)-(5>>2)&(01) =a+b+c;

对于32位的树来讲,可以分为11组,每组3位,第一组是两位,所以

m-(m>>1)&(033333333333)-(m>>2)&(011111111111)所得的结果就是每3位中1的个数所组成的32位数

比如5=0...000101=>0...000010

现在我们知道了,只要把每3位中表示的1的个数相加就可以了n11+...+n2+n1,第一行所得的结果可以表示成

2^10*n11+...+2^1*n2+2^0*n1,

也许你会想到

m%7=n11+...+n2+n1

但是犯了一个致命的错误,如果所得结果是1的个数是14,那么14%7=0;错误!

所以这里采取先两个3位相加成6位,也就是下面的代码

(m+(m>>3))&(030707070707)

然后%63 就是所得结果。

为什么&(030707070707)呢?这是为了不受前面进位的影响,

为什么是m+(m>>3)呢?这是因为3位二进制表示的是3原来3位二进制数的1的个数,大小不超过3,

所以2两个3位数加起来小于7,不会产生进位,可以直接相加。

如果还有什么不理解的可以发表评论,谢谢!

这个算法太强悍了,在此感谢露神~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值