BOP - 计算32位整型数中的1的个数
来源:互联网 发布:c指针编程之道 编辑:程序博客网 时间:2024/09/21 09:25
一、HAKMEM算法分析
1、整型数 i 的数值,实际上就是各位乘以权重——也就是一个以2为底的多项式:
i = A0*2^0+A1*2^1+A2*2^2+...
因此,要求1的位数,实际上只要将各位消权:
A0+A1+A2+... 即系数和就是'1'的个数。
2、定理:对任何自然数n的N次幂,用n-1取模得数为1。
证明:
若 n^(k-1) % (n-1) = 1 成立
则 n^k % (n-1) = ((n-1)*n^(k-1) + n^(k-1)) % (n-1) = 0 + n^(k-1) % (n-1) = 1 也成立
又有 n^(1-1) % (n-1) = 1
故对任意非负整数N, n^N %(n-1)=1
3、因此,对一个系数为{Ai}的以n为底的多项式P(N) = A0*n^N0+A1*n^N1+A2*n^N2+...
P(N)%(n-1) = (sum({Ai})) % (n-1) ;
如果能保证sum({Ai}) < (n-1),则 P(N)%(n-1) = (sum({Ai}))
也就是说,此时只要用n-1对多项式取模,就可以完成消权,得到系数和。
于是,问题转化为,将以2为底的多项式转化为以n为底的多项式,其中n要足够大,使得n-1 > sum({Ai})恒成立。
32位整型数中Ai=0或1,sum({Ai})<=32。n-1 > 32 ,n需要大于33。
因此取n=2^6=64>33作为新多项式的底。
4、将32位二进制数的每6位作为一个单位,看作以64为底的多项式:
i = t0*64^0 + t1*64^1 + t2*64^2 + t3*64^3 + ...
各项的系数ti就是每6位2进制数的个数。
这样,只要通过运算,将各个单位中的6位数变为这6位中含有的'1'的个数,再用63取模,就可以得到所求的总的'1'的个数。
5、取其中任意一项的6位数ti进行考虑,最简单的方法显然是对每次对1位进行mask然后相加,即
(ti>>5)&(000001) + (ti&>>4)(000001) + (ti>>3)&(000001) + (ti>>2)&(000001) + (ti>>1)&(000001) + ti&(000001)
1、整型数 i 的数值,实际上就是各位乘以权重——也就是一个以2为底的多项式:
i = A0*2^0+A1*2^1+A2*2^2+...
因此,要求1的位数,实际上只要将各位消权:
A0+A1+A2+... 即系数和就是'1'的个数。
2、定理:对任何自然数n的N次幂,用n-1取模得数为1。
证明:
若 n^(k-1) % (n-1) = 1 成立
则 n^k % (n-1) = ((n-1)*n^(k-1) + n^(k-1)) % (n-1) = 0 + n^(k-1) % (n-1) = 1 也成立
又有 n^(1-1) % (n-1) = 1
故对任意非负整数N, n^N %(n-1)=1
3、因此,对一个系数为{Ai}的以n为底的多项式P(N) = A0*n^N0+A1*n^N1+A2*n^N2+...
P(N)%(n-1) = (sum({Ai})) % (n-1) ;
如果能保证sum({Ai}) < (n-1),则 P(N)%(n-1) = (sum({Ai}))
也就是说,此时只要用n-1对多项式取模,就可以完成消权,得到系数和。
于是,问题转化为,将以2为底的多项式转化为以n为底的多项式,其中n要足够大,使得n-1 > sum({Ai})恒成立。
32位整型数中Ai=0或1,sum({Ai})<=32。n-1 > 32 ,n需要大于33。
因此取n=2^6=64>33作为新多项式的底。
4、将32位二进制数的每6位作为一个单位,看作以64为底的多项式:
i = t0*64^0 + t1*64^1 + t2*64^2 + t3*64^3 + ...
各项的系数ti就是每6位2进制数的个数。
这样,只要通过运算,将各个单位中的6位数变为这6位中含有的'1'的个数,再用63取模,就可以得到所求的总的'1'的个数。
5、取其中任意一项的6位数ti进行考虑,最简单的方法显然是对每次对1位进行mask然后相加,即
(ti>>5)&(000001) + (ti&>>4)(000001) + (ti>>3)&(000001) + (ti>>2)&(000001) + (ti>>1)&(000001) + ti&(000001)
二、代码
1、由上面分析可以得到代码:
这样又减少了几步!!
3、化简二
如何计算三位中1的个数,如三位abc,1的个数无非是计算 a+b+c
一个3位2进制数值是4a+2b+c
如果右移一位,变成2a+b;再右移一位,变成a
而(4a+2b+c) - (2a+b) - a = a+b+c 得到的就是我们想要的数
所以改代码如下:
1、由上面分析可以得到代码:
int bitcount(unsigned int n) { unsigned int tmp; tmp = (n &010101010101) +((n>>1)&010101010101) +((n>>2)&010101010101) +((n>>3)&010101010101) +((n>>4)&010101010101) +((n>>5)&010101010101); return (tmp%63); }
返回的就是1的个数。简单吧
2、化简一
上面是计算每六位中1的个数,得到上面原理分析的ti
但是,6位数中最多只有6个'1',也就是000110,只需要3位有效位,所以有些浪费
如果先得到每三位中1的个数,然后加一下也得到每六位1的个数,代码如下:
2、化简一
上面是计算每六位中1的个数,得到上面原理分析的ti
但是,6位数中最多只有6个'1',也就是000110,只需要3位有效位,所以有些浪费
如果先得到每三位中1的个数,然后加一下也得到每六位1的个数,代码如下:
int bitcount(unsigned int n) { unsigned int tmp; tmp = (n &011111111111) +((n>>1)&011111111111) +((n>>2)&011111111111); tmp = (tmp + (tmp>>3)) &03070707007; return (tmp%63); }
这样又减少了几步!!
3、化简二
如何计算三位中1的个数,如三位abc,1的个数无非是计算 a+b+c
一个3位2进制数值是4a+2b+c
如果右移一位,变成2a+b;再右移一位,变成a
而(4a+2b+c) - (2a+b) - a = a+b+c 得到的就是我们想要的数
所以改代码如下:
int bitcount(unsigned int n) { unsigned int tmp; tmp = n // 4a+2b+c - ((n >> 1) & 033333333333) // 2a+b - ((n >> 2) & 011111111111); // a tmp = (tmp + (tmp >> 3)) & 030707070707 return (tmp%63); }
这样又少了两步,这才是最最简单,复杂度最低的求1的个数的方法!!
转自:http://www.my1984.com.cn/article.asp?id=779
转自:http://www.my1984.com.cn/article.asp?id=779
- BOP - 计算32位整型数中的1的个数
- 计算整型数二进制中值为1的位的个数
- 32位int整型数的二进制表示中1的个数
- 计算32位整形数内含有1的个数
- 求一个32位二进制数中的1的个数
- 比特计算 - 整型中1的个数计算
- 计算无符号整型变量的二进制中的1的个数
- 整型数其二进制表示中”1“的个数
- BOP - 1的数目
- 求64位整型n,中各个bit位是1的个数
- 计算整型数的二进制中包含多少个1
- 计算二进制数中1的个数
- 计算二进制数中1的个数
- 计算整形数中1的个数
- 计算二进制数中1的个数
- 计算二进制数中1的个数
- 计算二进制数中1的个数
- 计算一个整数中的位是1或是0的个数的快速算法
- nagios + snmp配置,自己配出来,才能有收获!
- 日常邮件用语(二)
- 用C#实现基于TCP协议的网络通讯
- 【动态规划32讲】第四节 动态规划入门[不懂]
- 中国茶叶的影响
- BOP - 计算32位整型数中的1的个数
- 第12周报告3
- 学习jQuery的注意事项
- VC Studio6.0 使用技巧大全
- Unix script 12 - extrnal programs 外部程序
- SQL对Xml字段的操作
- 记录页面的cookie值
- flex中flash.events和mx.events的事件的区别
- VB图形绘制