编译成更快的代码:“n * 3”或“n +(n * 2)”?

编译成更快的代码:“ans = n * 3”或“ans = n +(n * 2)”?

假设n是int或long,它是在现代Win32 Intel盒子上运行的。

如果涉及一些解除引用,这会有所不同,也就是说,哪一个会更快?


长的;
 long * pn;
长的;

 ...
 * pn = some_number;
 ans = * pn * 3;

要么

 ans = * pn +(* pn * 2);

或者,它是否需要不用担心,因为优化编译器在任何情况下都可能解释这一点?

IMO这样的微优化不是必需的,除非你使用一些奇特的编译器。 我会把可读性放在第一位。

没关系。 现代处理器可以在一个时钟周期或更短的时间内执行整数MUL指令,这与需要执行一系列移位并在内部添加以执行MUL的旧处理器不同,从而使用多个周期。 我敢打赌

MUL EAX,3 

执行速度快于

 MOV EBX,EAX SHL EAX,1 ADD EAX,EBX 

这种优化可能有用的最后一个处理器可能是486.(是的,这偏向于英特尔处理器,但也可能代表其他架构)。

无论如何,任何合理的编译器都应该能够生成最小/最快的代码。 因此,首先要考虑可读性。

由于自己很容易测量,为什么不这样做呢? (使用来自cygwin的gcctime

 /* test1.c */ int main() { int result = 0; int times = 1000000000; while (--times) result = result * 3; return result; } machine:~$ gcc -O2 test1.c -o test1 machine:~$ time ./test1.exe real 0m0.673s user 0m0.608s sys 0m0.000s 

进行几次测试,然后重复测试另一种情况。

如果你想查看汇编代码, gcc -S -O2 test1.c

这取决于编译器,其配置和周围的代码。

如果不进行测量,你不应该试着猜测事情是否“更快”。

一般来说,你现在不应该担心这种纳米级优化的东西 – 它几乎总是完全不相关,如果你真正在一个重要的领域工作,你就已经在使用一个分析器并查看汇编语言输出编译器。

找出编译器对你的代码做了什么并不难(我在这里使用DevStudio 2005)。 使用以下代码编写一个简单的程序:

 int i = 45, j, k; j = i * 3; k = i + (i * 2); 

在中间行放置一个断点并使用调试器运行代码。 触发断点时,右键单击源文件并选择“转到反汇编”。 您现在将拥有一个包含CPU正在执行的代码的窗口。 在这种情况下,您会注意到最后两行产生完全相同的指令,即“lea eax,[ebx + ebx * 2]”(在这种特殊情况下不进行位移和添加)。 在现代的IA32 CPU上,由于CPU的流水线特性,在过早使用修改后的值时会造成损失,因此执行直接MUL而非位移可能更有效。

这表明了aku正在谈论的内容,即编译器足够聪明,可以为您的代码选择最佳指令。

它确实取决于您实际使用的编译器,但很可能它们转换为相同的代码。

您可以通过创建一个小测试程序并检查其反汇编来自行检查。

大多数编译器足够聪明,可以将整数乘法分解为一系列位移和加法。 我不知道Windows编译器,但至少使用gcc你可以让它吐出汇编程序,如果你看一下,你可以看到相同的汇编程序用于编写它的两种方式。

它并不关心。 我认为有更重要的事情需要优化。 你花了多少时间思考和编写这个问题,而不是自己编码和测试?

🙂

只要你使用一个不错的优化编译器,只需编写易于编译器理解的代码 。 这使编译器更容易执行巧妙的优化。

您问这个问题表明优化编译器比您更了解优化。 所以相信编译器。 使用n * 3

看看这个答案也是如此。

编译器擅长优化您的代码。 任何现代编译器都会为两种情况生成相同的代码,另外用左移代替* 2

相信你的编译器可以优化那些代码。 可读性在代码级别更重要。 真正的优化应该达到更高的水平。