二进制拆弹实验详解_Population Count算法-求二进制数中1的个数
所谓Population Count算法,即是指计算一个二进制数中1的个数的算法。具体来说,就是任意给定一个无符号整数N,求N的二进制表示中1的个数,比如N = 5(0101)时,返回2;N = 15(1111)时,返回4。
这个问题是一个经典的面试题目,在实际中也有应用。关于这个问题,以下两篇博客文章中有较详细的论述:
详解二进制数中1的个数算法-求二进制数中1的个数
在此,仅对其中一些较为常规和较为巧妙的方法做一总结,并比较一下他们的执行效率。
直接法1
直接逐位判断,最直接也是最低效的方法。
char CountOne1(unsigned int num){ char N = 8 * sizeof(num); char Count = 0; while (N--) { Count += num & 1; num >>= 1; } return Count;}
直接法2
在“直接法1”的基础上进行改进,当移位结果为0后就退出循环,这样循环次数与首位1的位置有关。最优情况下只循环一次,最坏情况下循环N次。
char CountOne2(unsigned int num){ char Count; for (Count = 0; num != 0; num >>= 1) { Count += num & 1; } return Count;}
逐次清除最低位1
此方法利用num &= (num - 1)可清除最低位1的原理进行计数。num与num - 1的区别在于,num的最低位1在num - 1中变为了0,故二者取与后即可清除最低位1.
int CountOne3(unsigned int num){ char Count; for (Count = 0; num != 0; Count++) { num &= (num - 1); } return Count;}
分支法
思路类似二分法,两两相加后即可得到结果,见下图:
在详解二进制数中1的个数中对此有详细描述。此方法复杂度为Log(N)(之前几种方法复杂度均为N),对于32位整数只需要计算5次即可。
char CountOne4(unsigned int num) { num = (num & 0x55555555) + ((num >> 1) & 0x55555555); num = (num & 0x33333333) + ((num >> 2) & 0x33333333); num = (num & 0x0f0f0f0f) + ((num >> 4) & 0x0f0f0f0f); num = (num & 0x00ff00ff) + ((num >> 8) & 0x00ff00ff); num = (num & 0x0000ffff) + ((num >> 16) & 0x0000ffff); return num ; }
三分法
这是一种很巧妙的方法,在此对其原理不多做说明,可参考之前提到的那两篇博客文章。
char CountOne5(unsigned int num){ unsigned int tmp = num - ((num >> 1) & 033333333333) - ((num >> 2) & 011111111111); return ( (tmp + (tmp >> 3) ) & 030707070707) % 63;}
CPU指令实现
部分CPU中直接提供了指令来完成这一操作,这无疑是效率最高且最为简洁的方法。
在Intel x86中,如果CPU支持SSE4指令集,那可以使用POPCNT指令来计算二进制数中1的个数,实验表明,这应该是一个单周期指令,所以这无疑是最优的解决方案。
在MSVC下,可通过_mm_popcnt_u32()函数来调用POPCNT指令,详细信息可参考MSDN上的帮助。调用示例如下:
#include Count = _mm_popcnt_u32(num);
在GCC下,可直接调用__builtin_popcountll()函数,编译时加上编译选项-mpopcnt即可,此时编译器会自动使用POPCNT指令。
在ARM中,也有类似的指令,比如POPCOUNT宏(需要约10个时钟周期),NEON SIMD指令集中的VCNT及CNT指令。
POPCNT指令应该是有其实际重要作用的,比如在OpenCV的编译过程中就可以选择是否启用POPCNT指令。
执行时间对比
毫无疑问,直接调用CPU指令是最佳的解决方案,将其执行时间规定为1,对其他算法的执行时间进行归一化处理,结果如下:
从中可以看到,除了特别简单的情况下(如0x01),分枝法与三分法的执行效率是最好的,且这两种算法是稳定的算法,其执行时间不依赖于输入数据。逐次清除最低位1法在1的个数较少时也不失为一种好方法。
二进制拆弹实验详解_Population Count算法-求二进制数中1的个数相关推荐
- 二进制拆弹实验详解linux,拆解二进制炸弹
拆解二进制炸弹 一.实验目的 1.理解C语言程序的机器级表示. 2.初步掌握GDB调试器的用法. 3.阅读C编译器生成的x86-64机器代码,理解不同控制结构生成的基本指令模式,过程的实现. 二. 实 ...
- 算法经典“钓鱼”问题详解 基于贪心算法 C语言描述
算法经典"钓鱼"问题详解 基于贪心算法 初始条件 在一条水平路边,有 n 2 ≤ n ≤ 25个钓鱼池,从左到右编号为1.2.3.--.n.小明有H1 ≤ H ≤ 16个小时的空余 ...
- 【算法知识】详解希尔排序算法
前言 已发布: [算法知识]详解选择冒泡算法 [算法知识]详解选择排序算法 [算法知识]详解插入排序算法 当待插入元素是一个很小(当需求是从小到大排序时,从大到小排序时此处为很大)直接插入排序需要移动 ...
- 【算法知识】详解直接插入排序算法
前言 已发布: [算法知识]详解选择冒泡算法 [算法知识]详解选择排序算法 在玩扑克牌的时候,我们抽到一张牌的时候,都是将它插入到当前手中牌的合适位置的. 如下图: (上图来自算法导论) 直接插入排序 ...
- 实验详解——Cobbler自动部署最小化安装
实验详解--Cobbler自动部署最小化安装 一.实验:自动部署 二.Cobbler自动装机服务搭建步骤 1.导入epel源并加载在线安装源 2.安装Cobbler以及其相关服务软件包 3.修改cob ...
- 实验详解——DNS网关服务器的分离解析
实验详解--DNS网关服务器的分离解析 一.实验图 二.要求 三.实验开始 1.网关服务器的配置 ①.新添加一块网卡,用双网卡来演示网关服务器的两个端口 ②.对两个网卡进行配置的修改 ③.重启网卡并查 ...
- 实验详解——DNS反向解析、DNS主服务器和从服务器的配置
实验详解--DNS反向解析.DNS主服务器和从服务器的配置 实验一:DNS反向解析 1.安装bind 2.查找配置文件路径 3.配置/etc/named.conf主配置文件 4.修改/etc/name ...
- 详解FTP服务完成Linux和WIN10之间的信息传输(实验详解)
详解FTP服务完成Linux和WIN10之间的信息传输(实验详解) 一.FTP简介 1. FTP服务--用来传输文件的协议 2.端口 3.数据连接模式 二.相关配置 1.安装FTP服务 2.设置匿名用 ...
- 详解 Linux环境中DHCP分配IP地址(实验详解)
Linux中DHCP小实验详解 一.DHCP中继概述 二.DHCP在linux系统中的相关配置 1.配置DHCP服务器 2.设置全局配置参数 3.subnet网段声明 4.host主机声明 三.实验例 ...
最新文章
- Xcode消除编译器警告
- 玩转Android- 收藏集 - 掘金
- python numpy.savetxt(),np.column_stack保存(多行/列)数据 保存多维数组
- Pat乙级 1040 有几个PAT
- [R]R语言中的%%和%.%
- android studio zlib,在Android Studio 3.1中构建项目时出现“压缩执行失败”错误
- 天池 在线编程 最大得分(DP)
- 003.DNS主从正反解析部署
- cdoj31-饭卡(card) (01背包)
- 15.卷2(进程间通信)---门
- MySQL安装配置教程(超详细!)
- 2021年全球探针卡市场规模大约为158亿元(人民币),预计2028年将达到247亿元
- “极狐•华为HI版本”的尴尬与困境
- Phaser 使用介绍
- JAVA操作共享文件夹文件、下载、读取(windows、Linux通用)
- 盘点:视频监控行业的潜在商机
- React Native学习资源汇总
- python-半省略号、三个点、点点点、...符号的用法小结
- 使用restormer网络做2022年中兴捧月图像去噪
- 烽火HG680-KA/KB_Hi3798MV310_红外蓝牙语音_开启无线开关_通刷固件包
热门文章
- Linux内核分析-孟宁
- 1026. 节点与其祖先之间的最大差值
- python的idle支持两种方式_BO发布E8 Sport耳机,支持IP57防水
- html5游戏面试题,关于HTML5的十大面试题
- linux 复制文件到另一个目录命令_每天一条Linux命令(21) scp (远程文件复制)
- python3.7.2安装与pycharm_Python3和PyCharm安装与环境配置【图文教程】
- python中mean的用法_python 的numpy库中的mean()函数用法介绍
- linux 软件 tar deb rmp,deb、rpm、tar.gz三种Linux软件包的区别
- swarm部署mysql_「实战篇」开源项目docker化运维部署-借助dockerSwarm搭建集群部署(九)...
- Ubuntu, python, CUDA, cuDNN, 驱动, GCC ....的对应关系