C++编译器是否通过两次操作优化乘以x*2
比特移位操作x<<1
?
我很乐意相信是的.
实际上VS2008将其优化为x + x:
01391000 push ecx int x = 0; scanf("%d", &x); 01391001 lea eax,[esp] 01391004 push eax 01391005 push offset string "%d" (13920F4h) 0139100A mov dword ptr [esp+8],0 01391012 call dword ptr [__imp__scanf (13920A4h)] int y = x * 2; 01391018 mov ecx,dword ptr [esp+8] 0139101C lea edx,[ecx+ecx]
在x64构建中,它更加明确并使用:
int y = x * 2; 000000013FB9101E mov edx,dword ptr [x] printf("%d", y); 000000013FB91022 lea rcx,[string "%d" (13FB921B0h)] 000000013FB91029 add edx,edx
这将是'最大化速度'(/ O2)的优化设置
Raymond Chen的这篇文章可能很有趣:
当x/2与x >> 1不同时?:http: //blogs.msdn.com/oldnewthing/archive/2005/05/27/422551.aspx
引用雷蒙德:
当然,编译器可以自由识别并重写乘法或移位操作.事实上,它很可能会这样做,因为x + x比乘法或移位更容易配对.您的移位或乘二可能会被重写为更接近添加eax,eax指令的东西.
[...]
即使您假设移位填充符号位,如果x为负,则移位和除法的结果也不同.
(-1)/2≡0
(-1)>>1≡-1[...]
故事的寓意是写出你的意思.如果要除以2,则写"/ 2",而不是">> 1".
我们只能假设告诉编译器你想要什么,而不是你想要他做什么是明智的:编译器优于人类优化小规模代码(感谢Daemin指出这个微妙点):如果你真的想要优化,使用分析器,并研究算法的效率.
VS 2008优化了我的x << 1.
x = x * 2; 004013E7 mov eax,dword ptr [x] 004013EA shl eax,1 004013EC mov dword ptr [x],eax
编辑:这是使用VS默认"调试"配置,禁用优化(/ Od).使用任何优化开关(/ O1,/ O2(VS"Retail")或/ Ox)会导致添加自我代码Rob发布.另外,为了好的测量,我验证x = x << 1
的确x = x * 2
与cl /编译器在/ Od和/ Ox中的处理方式相同.因此,总之,x86的cl.exe版本15.00.30729.01对待* 2
和<< 1
完全相同,我希望几乎所有其他最近的编译器都这样做.
如果x是浮点数则不会.
是.它们还优化了其他类似的操作,例如乘以2的非幂,可以将其重写为某些移位的总和.他们还将优化2的幂划分为右移,但要注意当使用有符号整数时,这两个操作是不同的!编译器必须发出一些额外的位错误指令,以确保正数和负数的结果相同,但它仍然比进行除法更快.它同样也以2的幂来优化模数.
答案是"如果它更快"(或更小).这很大程度上取决于目标体系结构以及给定编译器的寄存器使用模型.一般来说,答案是"是的,永远",因为这是一个非常简单的窥视孔优化实施,通常是一个不错的胜利.