C++中计算平方差a*a-b*b与(a+b)*(a-b)哪种执行速度更快?
C++实现平方差时
a*a-b*b与(a+b)*(a-b)的执行速度对比 单从算术操作计数看:
a*a-b*b需要完成2次乘法、1次减法(a+b)*(a-b)需要完成1次加法、1次减法、1次乘法
表面看第二种写法运算开销更低,但也有观点认为第一种写法加载数据到寄存器的次数更少,这部分优势可能抵消乘加操作的开销差,需要结合实际编译结果判断。
无优化编译的常量场景测试
不开启O系列编译优化,使用局部固定常量赋值的代码测试时,两种写法生成的汇编指令总数相同。
测试代码:
#include <iostream> int main() { int a = 6, b = 7; int c1 = a*a-b*b; int c2 = (a-b)*(a+b); return 0; }
int c1 = a*a-b*b;对应的汇编指令如下:
mov eax,DWORD PTR [rbp-0x4] imul eax,eax mov edx,eax mov eax,DWORD PTR [rbp-0x8] imul eax,eax sub edx,eax mov DWORD PTR [rbp-0xc],edx
int c2 = (a-b)*(a+b);对应的汇编指令如下:
mov eax,DWORD PTR [rbp-0x4] sub eax,DWORD PTR [rbp-0x8] mov ecx,DWORD PTR [rbp-0x4] mov edx,DWORD PTR [rbp-0x8] add edx,ecx imul eax,edx mov DWORD PTR [rbp-0x10],eax
观察指令类型可以发现:第一种写法有4条纯寄存器间操作指令,第二种写法仅2条纯寄存器间操作指令,其余都是内存与寄存器交互的指令。但这个场景的测试参考价值有限:无编译优化的生成结果本身不会做指令调度优化,且常量赋值场景下变量的内存分配是编译器按栈规则机械生成的,和实际生产环境运行的代码逻辑差异较大。
排除常量优化的验证测试
为了避免编译器在编译期直接对常量做计算折叠,我们调整测试逻辑:通过标准输入读取a、b的值,同时用volatile修饰结果变量,确保编译器无法提前获知变量取值、不会把计算逻辑优化掉。
测试代码如下:
#include <iostream> int dsq1(int a, int b) { return a*a-b*b; }; int dsq2(int a, int b) { return (a+b)*(a-b); }; int main() { int a,b; // 阻断编译期常量优化 std::cin >> a; std::cin >> b; volatile int c1 = dsq1(a,b); volatile int c2 = dsq2(a,b); return 0; }
编译结果显示:
a*a-b*b对应的函数共生成5条汇编指令,包含2次乘法运算:
mov esi,eax mov ecx,edx imul esi,eax imul ecx,edx sub ecx,esi
(a+b)*(a-b)对应的函数仅生成4条汇编指令,仅包含1次乘法运算:
mov ecx,edx sub ecx,eax add eax,edx imul eax,ecx
结论
(a+b)*(a-b)的执行速度快于a*a-b*b。
现代CPU架构中,整数乘法指令的执行延迟、占用的执行端口资源都远高于加法和减法指令,少一次乘法带来的性能收益,远超过少量寄存器数据移动操作的开销,这也是最终第二种写法性能更好的核心原因。
内容的提问来源于stack exchange,提问作者Sergiy Maksymenko
相关产品推荐
相关产品推荐

