当前位置: 首页 > news >正文

位运算卡常技巧详解

位运算卡常技巧详解

位运算的核心优势在于:它直接在二进制比特位上操作,避免了高级语言抽象带来的开销,一条指令就能完成多个比特位的并行计算。以下是七种常用且高效的位运算优化技巧。


1. 乘除2的幂:移位代替乘除
  • 技巧: 用左移(<<)和右移(>>)操作代替乘以或除以2的幂次方。

  • 原理: 整数在计算机中以二进制形式存储。左移一位等价于乘以2,右移一位等价于除以2(向下取整)。移位指令的执行速度远快于乘法指令。

  • 示例

    // 优化前
    int a = x * 32;
    int b = y / 8;
    int c = z % 4; // 求余也慢// 优化后
    int a = x << 5; // 2^5 = 32
    int b = y >> 3; // 2^3 = 8
    int c = z & 3;  // 见技巧2,对2^n取余等价于与(2^n - 1)进行与操作
    
2. 对2的幂取模:与操作代替取模
  • 技巧: 用按位与(&)操作代替对2的幂次方的取模(%)运算。

  • 原理: 一个数 x2^n 取模,实质就是获取 x 的低 n 位二进制值。这与和掩码 (2^n - 1) 进行按位与操作的效果完全相同。

  • 示例

    // 优化前
    int remainder = x % 16; // 求x除以16的余数// 优化后
    int remainder = x & 15; // 15的二进制是 1111,保留最后4位
    // 同样适用于哈希表桶数量的计算,如果桶数bucket_count是2的n次方
    int bucket_index = hash_value % bucket_count; // 慢
    int bucket_index = hash_value & (bucket_count - 1); // 快!
    
3. 判断奇偶性:与1代替模2
  • 技巧: 用 x & 1 代替 x % 2 来判断奇偶性。

  • 原理: 二进制的最低位为1则是奇数,为0则是偶数。x & 1 直接取出最低位,比取模运算快得多。

  • 示例

    // 优化前
    if (x % 2 == 1) { /* 是奇数 */ }
    if (x % 2 == 0) { /* 是偶数 */ }// 优化后
    if (x & 1) { /* 是奇数 */ }
    if (!(x & 1)) { /* 是偶数 */ } // 或 if ((x & 1) == 0)
    
4. 交换两个变量的值:异或交换
  • 技巧: 使用异或(^)操作在不引入临时变量的情况下交换两个整数。

  • 原理: 利用异或操作的性质:a ^ b ^ b = a

    • 第一步:a = a ^ b
    • 第二步:b = a ^ b -> b = (a ^ b) ^ b = a
    • 第三步:a = a ^ b -> a = (a ^ b) ^ a = b
  • 注意: 这是一个著名的技巧,但在现代CPU上,由于指令级并行和流水线技术,使用临时变量的方法通常更快,因为异或交换串行依赖严重。它更适用于寄存器紧张或作为趣味编程。

  • 示例

    // 传统方法(编译器可能已经优化得很好了)
    void swap(int &a, int &b) {int temp = a;a = b;b = temp;
    }// 异或交换方法
    void swap_xor(int &a, int &b) {a ^= b;b ^= a;a ^= b;
    }
    
5. 判断两数符号是否相同:异或代替乘法比较
  • 技巧: 用 (a ^ b) >= 0 来判断两个整数 ab 是否同号(即都是正数或都是负数)。

  • 原理: 整数的最高位是符号位(0正1负)。异或操作的特点是“相同为0,不同为1”。如果 ab 符号相同,则它们最高位的异或结果为0,整个 a ^ b 的结果必然是一个非负数(>=0);反之则为负数(<0)。

  • 示例

    // 优化前
    if (a * b > 0) { // 可能溢出!且乘法慢// 同号
    }// 优化后(安全且快速)
    if ((a ^ b) >= 0) {// 同号
    }
    
6. 取绝对值:无分支位运算
  • 技巧: 使用位运算实现无分支(Branchless)的绝对值计算,避免if判断带来的分支预测失败风险。

  • 原理

    1. int mask = x >> 31;: 对于32位有符号整数,算术右移31位会将符号位扩展到所有位。如果x是负数,mask0xFFFFFFFF(即-1);如果x是非负数,mask0
    2. (x ^ mask) - mask;
      • 如果x是负数(mask = -1):(x ^ -1) - (-1)x ^ -1 是对x按位取反,然后再+1,这正好是补码定义中求负数的方法,结果就是-x
      • 如果x是非负数(mask = 0):(x ^ 0) - 0 = x
  • 示例

    // 优化前(有分支)
    int abs_val = (x < 0) ? -x : x;// 优化后(无分支,对流水线友好)
    int abs_val = (x ^ (x >> 31)) - (x >> 31);
    // 或者另一种常见写法:
    int mask = x >> 31;
    int abs_val = (x + mask) ^ mask;
    
7. 快速计算二进制中1的个数(PopCount):使用内置函数
  • 技巧: 使用编译器内置函数 __builtin_popcount (GCC/Clang) 或 _mm_popcnt_u32 (Intel Intrinsics)。

  • 原理: 现代CPU(自SSE4.2起)有专门的POPCNT指令来执行这个操作。一条指令就能完成计算,速度远超任何手动实现的算法(如Brian Kernighan算法)。这是“用硬件指令降维打击”的典范。

  • 示例

    // 手动实现(Brian Kernighan算法,已很快,但仍不如硬件指令)
    int count_set_bits(int n) {int count = 0;while (n) {n &= (n - 1); // 清除最低位的1count++;}return count;
    }// 优化后(终极速度)
    int count = __builtin_popcount(x); // 对于GCC/Clang
    // #include <nmmintrin.h>
    // int count = _mm_popcnt_u32(x); // 对于MSVC和ICC等,需要包含头文件// 对于long long类型,使用 __builtin_popcountll
    

总结与注意事项

技巧优化前优化后原理
乘除2的幂x * 32, y / 8x << 5, y >> 3移位指令速度快
对2^n取模x % 16x & 15取模等价于取低位
判断奇偶性x % 2 == 0(x & 1) == 0直接检查最低位
判断符号相同a * b > 0(a ^ b) >= 0检查符号位异或结果
取绝对值x < 0 ? -x : x(x^mask)-mask无分支,避免预测失败
统计1的个数循环清除最低位__builtin_popcount使用专用CPU指令

重要提醒

  1. 可读性: 位运算会严重降低代码可读性。务必添加清晰的注释,说明你在做什么以及为什么这么做。
  2. 适用范围: 这些技巧主要针对整数有符号数的移位操作是实现定义(Implementation-defined) 的(通常使用算术移位)。确保你的操作在算术和逻辑上都正确。对于无符号数,移位总是逻辑移位,更安全。
  3. 编译器优化: 现代编译器在开启高优化等级(如-O2/-O3)时,通常能自动将 x * 2 优化为 x << 1。手动优化的意义更多在于编写编译器无法确定的复杂逻辑,或者在某些编译器优化能力较弱的场合。

熟练并合理地运用这些位运算技巧,能让你的程序在性能关键的循环中显著提升速度。

http://www.dtcms.com/a/351800.html

相关文章:

  • Charles抓包微信小程序请求响应数据
  • 信号无忧,转决千里:耐达讯自动化PROFIBUS集线器与编码器连接术
  • 快速了解卷积神经网络
  • springweb项目中多线程使用详解
  • 问:单证硕士含金量是否不足?
  • 【Linux 进程】进程程序替换
  • 【GitHub】使用SSH与GitHub交互
  • 工业大模型五层架构全景解析:从算力底座到场景落地的完整链路
  • PyCharm注释详解:TODO、文档注释、注释
  • MySQL 索引:结构、对比与操作实践指南
  • 【合适新人】预测图片教程——如何随机抽取验证集图片进行可视化推理!(附完整代码)
  • DigitalOcean GPU 选型指南(三):中端AI GPU性价比之王 RTX 4000 Ada、A4000、A5000
  • 无人机航拍数据集|第33期 无人机树冠目标检测YOLO数据集5842张yolov11/yolov8/yolov5可训练
  • 【HZ-T536开发板免费体验】无需死记 Linux 命令!用 CangjieMagic 在 HZ-T536 开发板上搭建 MCP 服务器,自然语言轻松控板
  • Java大厂面试全真模拟:从Spring Boot到微服务架构实战
  • 文本转语音TTS工具合集(下)
  • 【强化学习】区分理解: 时序差分(TD)、蒙特卡洛(MC)、动态规划(DP)
  • 计算机底层硬件实现及运行原理通俗书籍推荐
  • 记一次MySQL数据库的操作练习
  • 把 AI 塞进「空调遥控器」——基于 MEMS 温湿阵列的 1 分钟极速房间热场扫描
  • 如何获取当前页面html元素的外层容器元素
  • vscode或者cursor配置使用Prettier - Code formatter来格式化微信小程序wxss/wxs/wxml文件
  • Vue Flow 设计大模型工作流 - 自定义大模型节点
  • 基于XiaothinkT6语言模型的文本相似度计算:轻量方案实现文本匹配与去重
  • 乳腺癌数据集支持向量机实践学习总结
  • 2025最新的软件测试热点面试题(答案+解析)
  • OnlyOffice 渲染时间获取指南
  • from中烟科技翼支付 面试题2
  • 项目集升级:顶部导览优化、字段自定义、路线图双模式、阶段图掌控、甘特图升级、工作量优化、仪表盘权限清晰
  • 用大语言模型提升语音翻译:一种全新的端到端方法