位移运算对2的幂次方乘除具有确定性、无分支等优势,是安全高效起点;非2的幂需拆解为移位与加减组合,但需权衡精度与复杂度。

在多数现代编译器和通用处理器上,对2的幂次方做乘除时,位移运算确实能带来可测的性能优势——尤其在嵌入式系统、内核代码或高频循环中。但它的价值不在于“绝对更快”,而在于确定性、无分支、无浮点依赖、零函数调用开销。真正显著提升性能的关键,是结合场景选对用法,并规避常见陷阱。
只对2的幂次方使用位移,是最安全高效的起点
当操作数明确为2n(如×4、÷8、×1024),位移是等价且最优解:
-
×2n → 左移
n位:x (例如 <code>x * 64改为x ) -
÷2n(无符号或非负整数)→ 右移
n位:x >> n(例如y / 16改为y >> 4) - Linux FAT驱动中用
nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >> sbi->cluster_bits,正是因cluster_size恒为2的幂,cluster_bits是预存的 log₂ 值,避免每次重复计算幂和除法
非2的幂整数:拆解为移位+加减,但需权衡精度与复杂度
像 ×7、×13 这类运算,可分解为多个2的幂之和/差,再组合位移与加减:
-
a * 7→(a (因 7 = 8 − 1) -
a * 10→(a (因 10 = 8 + 2) -
a * 97→ 可拆为(a (64 + 32 + 1),但此时指令数已接近硬件乘法,收益递减 - 注意:涉及有符号负数时,左移可能溢出;右移负数行为由编译器定义(算术右移 vs 逻辑右移),应优先用
unsigned类型或显式转换
替代取模与整除:用位与和移位绕过昂贵除法
当模数是2的幂(如 %8、%64),位与比取模快一个数量级:
-
x % 8→x & 7(因 8 = 2³,掩码为 2³−1 = 7) -
x % 256→x & 0xFF - 组合使用:求块内偏移 + 块号,如文件系统中
block_no = offset >> dir_per_block_bits,entry_in_block = offset & ((1 - 对非2的幂模数(如 %100),不建议强行位移模拟;应考虑查表、乘法逆元(如
x / 100 ≈ (x * 0x28F5C29) >> 32)或直接接受编译器优化
实际提效的三个前提条件
位移提速不是“写了就快”,它依赖于运行环境与编码方式:
- 目标平台无硬件乘除加速:ARM Cortex-M0、RISC-V 基础核、8位单片机中效果最明显;x86-64 上乘法指令已极快,差异常被流水线掩盖
- 变量生命周期短、路径热:在中断服务程序、像素处理循环、网络包解析等每秒执行百万次的路径中,省下1–2个周期即显著
-
编译器未自动优化:启用
-O2后,GCC/Clang 通常会将x * 16自动转为x ;手动替换的价值在于你控制了行为(如确保无符号语义、避免符号扩展)
本质上,位移替代乘除不是炫技,而是把“数学意图”映射到“硬件直觉”。它在底层系统、实时控制、资源受限场景里依然锋利,但前提是清楚知道你在优化什么、为何要绕过编译器——而不是把它当成万能银弹。











