搜索
bottom↓
回复: 13
打印 上一主题 下一主题

精妙的算法3,4个循环就可以计算8位二进制中1的个数

[复制链接]

出0入0汤圆

跳转到指定楼层
1
发表于 2022-8-16 22:38:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 cnxh 于 2022-8-16 22:40 编辑

网上找的

如何计算二进制中1的个数?

全部遍历一遍?

不……不……这不是最优解……

下面看一段代码:

int bitcount (unsigned int n)
{
    int count=0 ;
    while (n) {
        count++ ;
        n &= (n - 1) ;
    }
    return count ;
}

太巧啦~

刚看到这个代码的时候,觉得这个解法真是太巧啦、太精妙啦(不要怪我没见过世面 )~

下面我们来理解一下这个代码,这个代码中核心的代码只有一行,就是 n &= (n - 1) ,我们分开看一下:
1. n-1:一个二进制的数减1,就是将这个二进制最右边的那个1变成0,然后它后边的所有位置都变成1~ 举例:0011 0100,减1(n-1)后变成:0011 0011。
2. n &= (n-1),并操作就会将有0的位置都变成0,上面的例子的结果就是0011 0000,然后再赋值给n,这时n就去掉了一个1,或者叫做计数了一个1。以此类推,就可以得到1的个数。

0011 0100 - 1 = 0011 0011   
0011 0100 & 0011 0011 = 0011 0000  // 计数一个1
0011 0000 - 1 = 0010 1111
0011 0000 & 0010 1111 = 0010 0000  // 计数两个1
0010 0000 - 1 = 0001 1111
0010 0000 & 0001 1111 = 0000 0000  // 计数三个1,程序停止

这样只需要循环3次,而如果直接遍历就会循环6次,性能明显提高啦~

给个极端的例子 1000 0000,这个直接遍历得遍历8次,而通过上面的代码只需要遍历

1次~1次~~1次~~~

真是太精妙啦~

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入442汤圆

2
发表于 2022-8-16 22:52:31 来自手机 | 只看该作者
业内广泛使用popcnt算法:a=((a&0xaaaaaaaa)>>1)+(a&0x55555555);
下面的换成0xcccccccc,2,0x33333333
0xf0f0f0f0,4,0x0f0f0f0f,
0xff00ff00,8,0x00ff00ff,
0xffff0000,16,0x0000ffff。
这是计算32位popcnt。新cpu都有popcnt指令。。

出0入12汤圆

3
发表于 2022-8-16 23:06:19 | 只看该作者
对于8位数,最多也要8个循环。

出0入362汤圆

4
发表于 2022-8-16 23:23:41 | 只看该作者
这个我算过, 链接: https://zhuanlan.zhihu.com/p/129377700
就不复制粘贴过来了.

8位的话, 感觉查表法应该能再快一点.

出0入42汤圆

5
发表于 2022-8-17 00:09:10 来自手机 | 只看该作者
谢谢分享,学习了

出0入85汤圆

6
发表于 2022-8-17 00:11:58 来自手机 | 只看该作者
上大学时搞过ACM,这个小意思了。印象中还有个利用状态转移计算1个数的,效率更高。全忘光了。   记得树状数组也有个类似的牛叉位运算,当年也是被震惊的不行

出0入0汤圆

7
发表于 2022-8-17 01:10:39 | 只看该作者
计算1的个数有什么目的?

出0入475汤圆

8
发表于 2022-8-17 01:44:44 来自手机 | 只看该作者
jetbo 发表于 2022-8-17 01:10
计算1的个数有什么目的?
(引用自7楼)

比如说,在一些资源或者类似的缺乏的地方,用每个bit表示有多少个状态,例如一个字节的8bit代表了8个故障信息,而不需要8个字节,而你需要对外提供你当前有多少个故障,那么就要看一下这个故障字节里面有多少个1了。
我只是简单的说明他的意义,并不需要来确定难道不能再找一个字节来表示故障个数吗?
当然可能还有其他的比如数学方面的用途,我就不得而知了,

出0入4汤圆

9
发表于 2022-8-17 08:38:13 | 只看该作者
循环次数跟1的个数有关

出0入0汤圆

10
发表于 2022-8-17 13:16:30 来自手机 | 只看该作者
单字节查表最好用了,四个字节就查四次相加

出0入71汤圆

11
发表于 2022-8-17 14:40:23 | 只看该作者
8位循环3次太多了,可以考虑4个位一组进行查表,这样两次就搞定,
如果是8位机,FLASH够多,直接8位查表,32位也只需要4次

出0入0汤圆

12
发表于 2022-8-17 19:50:14 | 只看该作者
确实很精妙,最近写个二进制平均分配算法,给定长度,设任意一个数都能以二进制形式平均分布,开始以为很简单,结果写了一天也没调好。

出0入0汤圆

13
 楼主| 发表于 2022-8-18 07:17:55 | 只看该作者
1a2b3c 发表于 2022-8-17 01:44
比如说,在一些资源或者类似的缺乏的地方,用每个bit表示有多少个状态,例如一个字节的8bit代表了8个故障 ...
(引用自8楼)

现在用串口模拟发送,需要校验位计算

出0入18汤圆

14
发表于 2022-8-18 07:36:13 来自手机 | 只看该作者
谢谢分享。  
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-28 10:17

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表