为何乘法与除法在此基准测试中执行速度相当?技术问询
为什么乘法和除法的基准测试结果速度相当?
嘿,这个问题其实挺常见的,尤其是刚接触性能基准测试的时候!我帮你拆解一下可能的核心原因,以及对应的解决办法:
1. 编译器的激进优化(最可能的原因)
现代编译器(比如GCC、Clang、MSVC)会对常数除法做乘法逆元优化——简单来说,如果你的代码里是除以一个固定的常数(比如x / 2、x / 3),编译器会把除法操作替换成乘法+移位的组合,因为这俩操作的速度比原生除法快得多。
举个例子,除以2其实等价于右移1位,除以3的话,编译器会找到一个特殊的整数,让x * 这个数之后再移位就能得到和x / 3一样的结果。这种情况下,你的“除法测试”其实跑的是乘法+移位,自然和纯乘法的速度差不多。
要验证这点很简单:把除数改成运行时才能确定的变量(比如从命令行输入、或者用一个非const的全局变量),编译器就没法提前做这个优化了。
2. 现代CPU的硬件特性
现在的CPU(比如x86的AVX系列、ARM的NEON)对除法的硬件支持已经比早年强很多:
- 很多CPU有专门的除法运算单元,并且支持流水线处理——也就是说,CPU可以同时执行多个除法操作,把整体吞吐量提上来,单个除法的延迟差异被掩盖了。
- 部分指令集(比如x86的
DIVSD)的除法延迟已经和乘法(MULSD)的差距缩小了不少,尤其是在处理浮点数的时候。
3. 你的测试循环可能被编译器“蒸发”了
如果你的循环体太简单,哪怕加了累加器,编译器也可能直接在编译期算出累加结果,然后把整个循环删掉——比如下面这段代码:
long sum = 0; for (int i = 0; i < 1000000; i++) { sum += i / 2; } printf("%ld", sum);
编译器会直接计算出sum的固定值,运行时根本不会执行循环,自然耗时几乎为0。解决办法同样是让循环依赖运行时变量(比如循环次数从命令行传入)。
4. 测试方法的精度问题
如果你的计时工具精度不够(比如用clock()函数,精度通常是毫秒级),而循环耗时又很短(比如小于1ms),就会显示耗时为0,或者两者的差异被误差淹没。
建议用高精度计时工具:
- C++可以用
std::chrono::high_resolution_clock - Python用
time.perf_counter() - 原生x86可以用
rdtsc指令读取CPU周期数
另外,要增加循环次数(比如跑到1e8次),让总耗时足够长,这样计时结果的误差才会更小。
给你的测试优化建议
- 用运行时变量作为除数和循环次数,避免编译期优化;
- 开启编译器优化(比如
-O2或-O3)——这才是实际程序的运行环境; - 使用高精度计时,多次测试取平均值;
- 如果想看到最原始的除法性能,可以临时关闭编译器优化(
-O0),但这不是生产环境的真实情况。
内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

