C/C++中__builtin_popcount()的使用及原理

高效位运算:揭秘__builtin_popcount 本文深入解析了C++中__builtin_popcount函数的原理与应用。作为统计二进制数中1的个数的关键工具,该函数通过硬件指令(如POPCNT)实现高效计算,性能比软件算法快3-7倍。文章详细介绍了其底层原理、语法特性、跨平台兼容方案,以及在密码学、图形学、网络协议等领域的实际应用。同时对比了不同编译优化下的性能差异,并展望了C++20标准中新引入的std::popcount。通过掌握这一底层优化技术,开发者能够在系统编程、算法优化等场景中显著提升程序性能。 阅读详情
AI摘要

本文介绍了三种高效计算二进制中‘1’的数量的方法:二分法通过位运算逐步减少计算复杂度;末位清零法巧妙地利用位运算特性逐次去除最低位的‘1’;哈希法(查表法)则通过预先计算好的查找表快速得出结果。这些方法各有优势,在不同场景下可灵活选择。

这个函数功能:返回输入数据中,二进制中‘1’的个数。

对于不同的使用类型,可以采用采用以下函数:

__builtin_popcount = int
__builtin_popcountl = long int
__builtin_popcountll = long long

1. 二分法,源码采用的方法

主要思路是:将相邻两位相加,可以实现用二进制来表示输入数据中‘1’的个数。然后依次将上半部分和下半部分相和并实现计数。

unsigned popcount (unsigned u)
{
    u = (u & 0x55555555) + ((u >> 1) & 0x55555555);
    u = (u & 0x33333333) + ((u >> 2) & 0x33333333);
    u = (u & 0x0F0F0F0F) + ((u >> 4) & 0x0F0F0F0F);
    u = (u & 0x00FF00FF) + ((u >> 8) & 0x00FF00FF);
    u = (u & 0x0000FFFF) + ((u >> 16) & 0x0000FFFF);
    return u;
}

算法案例如下:
这个二分法的原理:
用8位二进制数来做示范好了,例如 u = 10110011。
10110011
00010001 //每两位取1位,即取偶数位, u & 01010101
01010001 //取奇数位并右移一位, (u >> 1) & 01010101
---------------
01100010 //上面两数相加,赋值给u,注意每两列相加的结果不会进位到第三列
00100010 //每四位取低两位, u & 00110011
00010000 //每四位取高两位并右移两位, (u >> 2) & 00110011
---------------
00110010 //上面两数相加,赋值给u
00000010 //每八位取低四位, u & 00001111
00000011 //每八位取高四位并右移四位,(u >> 4) & 00001111
---------------
00000101 //上面两数相加,赋值给u
最终结果 u = 5。
在这里插入图片描述

方法二:末位清零

这个方法还是很常见的,利用一个数字减1之后,原来数字最后一个‘1’的位置一定会变成0,然后利用与&操作来实现清零最后一位。

unsigned popcnt (unsigned u)
{
    unsigned ret = 0;
    while (u)
        {
        u = (u & (u - 1));    // 将 u 最右边的 1 清除
        ret ++;
        }
    return ret;
}

方法三:哈希法(查表法)

这种方法感觉是最快的一种,但是也是最笨的吧。(可是我也没想到这种做法),实现原理就是把1个字节(8位),每个数字(0~255)所对于的个数记录下来,一直查表就可以了。

char poptable [256] =
{
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
unsigned __builtin_popcount (unsigned u)
{
    return poptable [u & 0xFF] + poptable [(u >> 8) & 0xFF] + poptable [(u >> 16) & 0xFF] + poptable [(u >> 24) & 0xFF];

反思:这种方法自己竟然没有想到,虽然看起来很笨,但是实际应用中,应该是最高效的实现。
思路上思考算法时,最好将时间最快,空间最小当作两个极端情况来思考。

参考博客:

C/C++中__builtin_popcount()的使用及原理

__builtin_popcount defined only for int?
GG的四种方法

C/C++: __builtin_popcount 函数及其一些 __builtin函数 __builtin_popcount函数 __builtin_popcount()用于计算一个 32 位无符号整数有多少个位为1 GCC有一个叫做__builtin_popcount的内建函数,它可以精确的计算1的个数。尽管如此,不同于__builtin_ctz,它并没有被 翻译成一个硬件指令(至少在x86上不是)。相反的,它使用基于表的方法来进行位搜索。这无疑很高效并且非常方便。 这个函数主要是我在刷题的过程中发现答案中这样判断的,我之前的判断方式一直是自己写一个函数,这种内建的库函数无疑更加高效 i 阅读详情

相关推荐

__builtin_xxx指令学习【3】__builtin_popcount & __builtin_popcountll

__builtin_popcount是GCC和Clang编译器提供的一个内置函数,用于计算一个整数中二进制位为1的个数。该函数的使用背景是在一些位运算和计算机视觉等领域中,需要对二进制数据进行处理和分析

hanhan的博客 1793

C语言popcount函数,C/C++中__builtin_popcount()的使用及原理详解

__builtin_popcount()用于计算一个 32 位无符号整数有多少个位为1Counting out the bits可以很容易的判断一个数是不是2的幂次:清除最低的1位(见上面)并且检查结果是不是0.尽管如此,有的时候需要直到有多少个被设置了,这就相对有点难度 了。GCC有一个叫做__builtin_popcount的内建函数,它可以精确的计算1的个数。尽管如此,不同于__builti...

weixin_29292535的博客 6816

C/C++编译器内建函数原理与性能优化实战

编译器内建函数是编程语言与硬件指令集之间的桥梁,通过直接映射特定机器指令实现底层优化。这类函数通常涉及原子操作、位运算和内存访问等核心计算概念,能够突破语言规范限制,为高性能计算、嵌入式开发等场景提供绿色通道。以GCC的__builtin_popcount和__sync_fetch_and_add为例,前者直接生成POPCNT指令实现高效位计数,后者提供无锁原子操作能力。在图像处理、高频交易等性能敏感领域,合理使用内建函数可获得10倍以上的性能提升。现代C++标准虽已引入原子操作等替代方案,但内建函数在指令

weixin_30420305的博客 348

编译器内置函数__builtin_popcount()

这个函数对于一些计算整数二进制表示中 1 的个数的算法非常有效,因为它利用了硬件的位操作指令或编译器优化,可以快速计算出结果,而不需要使用循环或逐位检查的方式。是一个内置函数,用于计算一个无符号整数的二进制表示中的 1 的个数。该函数在很多编译器(如GCC和Clang)中提供,旨在提供高效的位计数操作。是一个编译器内置函数,它只在特定的编译器中有效。在其他编译器中,可能需要使用其他方式实现相同的功能。例如,对于整数 9 的二进制表示为 1001,其中有两个 1,因此。的二进制表示中 1 的个数。

m0_65736560的博客 1934

C++20位操作新纪元:深入解析bit_width与popcount的实战应用

位运算是计算机底层编程的核心概念之一,它直接操作二进制位,是理解计算机数据表示和内存管理的基础。其原理在于利用CPU的位操作指令,对整数类型进行高效的逻辑与算术运算。掌握位运算技术对于实现高性能算法、优化数据结构和内存使用具有重要价值,广泛应用于位图、布隆过滤器、状态压缩和哈希计算等场景。C++20标准引入的<bit>头文件,特别是std::bit_width和std::popcount函数,将常用的位操作标准化,并借助编译器优化和硬件指令(如POPCNT)大幅提升性能,标志着从手动实现到标准化、高效位操作

417

编译器内建函数详解:从__builtin_expect到溢出检测的性能优化指南

在系统级开发与性能优化中,编译器不仅仅负责语法翻译,更提供了内建函数这一底层语义扩展机制。它允许开发者以函数调用的形式向编译器传递意图,从而生成更高效的机器指令。分支预测、位运算、溢出检测等基础操作,在GCC、Clang与MSVC等不同编译器中存在命名与行为差异,理解其原理有助于写出兼具性能与可移植性的代码。通过封装跨平台宏,可在不牺牲安全性的前提下,将高频操作如__builtin_popcount、__builtin_ctz映射为单条CPU指令,显著提升程序运行效率。这类技术广泛应用于内核、协议栈、嵌入式

weixin_34094282的博客 273

__builtin_popcount()函数

__builtin_popcount` 是 GCC 和 Clang 编译器提供的一个 **内置函数**,用于计算一个整数的二进制表示中 **1 的个数**(即 population count)。为了检查当前组合是否选择了 `p` 种饲料,我们可以使用 `__builtin_popcount(mask)` 来统计 `mask` 中 `1` 的个数。// 输出 3,因为 1101 中有 3 个 1。- `__builtin_popcount` 是一个高效的函数,用于统计整数的二进制表示中 `1` 的个数。

jsj的博客 911

BrainVision Recorder 和 BrainVision Analyzer 2.2 安装

本篇为《EEG处理》系列博客的第二篇,该系列博客主要记录EEG信号处理的学习过程中的软件安装和学习过程,方便以后查阅。本篇为BrainVision Recorder 和 BrainVision Analyzer 2.2 的安装过程。 BrainVision Recorder 和 BrainVision Analyzer 2.2 安装安装前奏Brain Vision Analyzer分析软件 安装Brain Vision Recorder记录软件 安装推荐几款个人使用的科研软件 安装前奏 Brain V

梁小憨憨的博客 5059

C语言popcount函数,C/C++中__builtin_popcount()的使用及原理

__builtin_popcount()用于计算一个 32 位无符号整数有多少个位为1Counting out the bits可以很容易的判断一个数是不是2的幂次:清除最低的1位(见上面)并且检查结果是不是0.尽管如此,有的时候需要直到有多少个被设置了,这就相对有点难度了。GCC有一个叫做__builtin_popcount的内建函数,它可以精确的计算1的个数。尽管如此,不同于__builtin...

weixin_34245171的博客 2316

Circos图审美拯救计划:用TBtools复刻Nature级共线性分析图谱

本文针对Circos图在共线性分析中的审美提升问题,提供了一套基于TBtools的完整优化方案。通过构建和谐的色彩体系、精细控制信息层布局以及模仿顶刊构图逻辑,详细讲解了如何从配色、透明度、标签显示到高级参数设置,将默认图表升级为具有高级学术美感的Nature级图谱,助力研究者提升论文图表质量。

cherry的博客 910

Keil开发中CMSIS Driver API缺失问题的排查与解决

本文详细解析Keil开发中CMSIS Driver API缺失问题的根源与解决方案。针对版本不匹配、安装不完整等常见原因,提供在线与离线安装的对比及详细排查步骤,重点涵盖版本兼容性分析与项目配置验证,帮助开发者彻底解决API缺失错误并预防问题复发。

rust6ferris的博客 550

C/C++ 前导零统计函数__builtin_clz() 和 统计二进制中为1的位数的函数__builtin_popcount()

此函数可以用来优化整数位运算或者在需要统计前导零的情况下使用。

weixin_41576682的博客 4353

服务器基础知识介绍

服务器,不仅仅是一台高性能计算机,更是网络的核心节点,承担着网络服务的责任。然而,相较于普通计算机,服务器对于稳定性、安全性和性能等方面提出了更高的要求,这使得它们在数字化浪潮中傲然独立。在硬件成本结构中,CPU和芯片组占据约50%的成本,内存占15%,外部存储占10%,其余硬件约占25%。服务器的逻辑结构与普通计算机相似,但由于其需要提供高性能计算,对稳定性、可靠性、安全性、可扩展性和可管理性的要求更高。服务器的分类多种多样,根据产品形式可分为塔式服务器、机架服务器、刀片服务器和机柜服务器。

m0_73576645的博客 1879

深入理解编译器内建函数:从__builtin_expect到popcount的性能优化实战

C/C++编译器除了语法翻译,还内置了一批特殊函数——内建函数(Built-in Functions)。它们能直接映射到硬件指令,如CPU位操作、分支预测、原子操作等,是性能优化的重要利器。理解内建函数的原理,可以帮助开发者在位图统计、协议解析、无锁编程等场景中大幅提升效率。本文从编译器优化机制切入,系统梳理GCC/Clang内建函数的分类与用法,重点剖析__builtin_popcount、__builtin_expect、__builtin_ctz等高频函数,并给出跨编译器移植的避坑指南。

weixin_34116482的博客 292

STM32 SPI驱动TFT LCD实战:时序配置与硬件协同

SPI(串行外设接口)是一种高速、全双工、同步串行通信协议,广泛应用于微控制器与显示模组等外设的数据交互。其核心依赖时钟极性(CPOL)与时钟相位(CPHA)组合定义的四种工作模式,直接影响数据采样可靠性;而片选(NSS)与MOSI/SCLK等信号的硬件映射,则决定了多设备共总线下的通信稳定性。在TFT LCD驱动场景中,SPI凭借低开销、高吞吐优势成为主流选择,尤其适配ST7789、ILI9341等集成显示控制器的模块。本文聚焦STM32L系列MCU通过SPI2驱动1.3寸LCD的完整链路,涵盖Mode

php55的博客 1208

EPO: Hierarchical LLM Agents with Environment PreferenceOptimization

长期决策和规划任务依然是基于大型语言模型(LLM)的智能体面临的一大挑战(Valmeekam 等,2023;Liu 等,2023;Silver 等,2024)。这些任务需要智能体进行多步骤的规划,同时保持行为的一致性和目标导向,这对于通常被设计用于即时和局部预测的大型语言模型来说颇为困难。此外,针对具身智能体的大型语言模型微调面临的一个关键难题是大规模标注数据的需求(Reed 等,2022)。

qq_52053775的博客 142

C/C++内建函数深度解析:原理、性能与跨平台实战

内建函数(Built-in Functions)是编译器在中间表示(IR)层直接识别并替换为底层指令的特殊语法机制,区别于宏、库函数和语法糖。其核心原理在于编译期语义识别与LLVM intrinsic映射,通过消除调用开销、符号解析、运行时检查及指令冗余四层成本,实现接近硬件指令级的执行效率。技术价值体现在确定性加速(如__builtin_popcountll)、架构感知操作(如__builtin_clz)和特权语义表达(如__builtin_assume)。广泛应用于高性能计算、嵌入式系统、实时音视频及底

weixin_33788244的博客 386

《UDS协议从入门到精通》系列——图解0x83:访问时间参数

详细介绍UDS协议0x83服务,目标ECU的时序参数设置有哪些注意点?

车载系统攻城狮 2138

C++位运算实战:从算法优化到汇编指令的深度解析

位运算作为计算机科学中的基础运算,通过直接操作二进制位实现高效计算。其核心原理是利用与、或、异或、移位等操作对数据的二进制表示进行精确控制,从而在底层实现复杂逻辑。这种技术价值在于能以近乎零成本完成其他方法需要复杂逻辑才能实现的功能,尤其在性能优化、硬件接口处理和算法竞赛中作用显著。在C++开发中,位运算常用于计算二进制中1的个数(Population Count)、标志位管理、数据压缩等场景。本文以计算无符号整数中1的个数为例,通过五种解法——包括朴素的循环法、Brian Kernighan优化技巧、编译

weixin_30430169的博客 454

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

C++位操作深度解析:从基础原理到高性能实战应用

位操作是计算机科学中的基础概念,它直接操作数据的二进制位,是连接高级编程语言与底层硬件效率的关键桥梁。其核心原理基于布尔代数,通过按位与、或、异或、移位等运算实现对数据的精细控制。这项技术的核心价值在于能够实现极致的性能优化和内存高效利用,尤其在资源受限或性能敏感的场景中至关重要。在工程实践中,位操作广泛应用于紧凑标志位系统、高效集合运算、网络协议解析、加密算法和硬件交互等场景。本文聚焦于C++中的位操作艺术,深入探讨了C++20引入的<bit>头文件等现代工具,并详细解析了掩码操作、位域处理等实战技巧,帮

weixin_33824363的博客 417

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

汉明距离算法详解:从位运算到高效实现

在计算机科学中,位运算是直接操作二进制数据的基础技术,它通过逻辑门级别的操作实现高效计算。其核心原理是利用CPU的位操作指令,在单个时钟周期内完成对数据位的并行处理,从而在算法优化和系统底层开发中发挥关键作用。位运算的技术价值在于能够极大提升程序性能,减少内存占用,广泛应用于数据压缩、加密算法、网络协议和嵌入式系统等领域。例如,在计算两个整数的差异时,通过异或运算和位计数技巧,可以高效求解汉明距离,这是错误检测、信息检索和基因序列分析等场景中的常见需求。本文深入探讨了汉明距离的多种实现方案,包括Brian

weixin_33709590的博客 489
上一篇: 竞赛回顾:脊柱疾病智能诊断大赛
下一篇: 红外热成像的空间分辨率怎么算?
dlvector
博客等级 码龄10年 85粉丝 142原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值