哪个编译为更快的代码:" n * 3"或者" n +(n * 2)"?
哪个编译为更快的代码:" ans = n * 3"或者" ans = n +(n * 2)"?
假设n是一个int或者long,并且它正在现代的Win32 Intel机器上运行。
如果涉及一些取消引用,这会有所不同吗,也就是说,哪些引用会更快?
long a; long *pn; long ans; ... *pn = some_number; ans = *pn * 3;
或者
ans = *pn+(*pn*2);
还是不必担心,在任何情况下优化编译器都可能会解决这一问题?
解决方案
回答
除非我们使用某些特殊的编译器,否则IMO不需要这种微优化。我将可读性放在首位。
回答
它确实取决于我们实际使用的编译器,但是很可能它们会转换为相同的代码。
我们可以通过创建一个小的测试程序并检查其拆卸情况来自己检查它。
回答
大多数编译器足够聪明,可以将整数乘法分解为一系列的移位和加法运算。我不了解Windows编译器,但是至少使用gcc可以使它吐出汇编器,而且如果我们看到它,则可能在两种编写方式上都可以看到相同的汇编器。
回答
编译器擅长优化代码。任何现代的编译器在这两种情况下都会产生相同的代码,并另外向左移动* 2.
回答
这将取决于编译器,其配置和周围的代码。
如果不进行测量,我们不应尝试猜测事物是否"更快"。
通常,如今我们不必担心这种纳米级优化的东西,它几乎总是完全无关紧要的,并且,如果我们确实在重要的领域中工作,那么我们已经在使用探查器并查看该程序的汇编语言输出。编译器。
回答
由于自己测量很容易,为什么不这样做呢? (使用来自Cygwin的gcc
和time
)
/* 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"。
回答
没关系现代处理器可以在一个时钟周期或者更短的时钟周期内执行整数MUL指令,这与较旧的处理器不同,后者需要执行一系列移位并在内部进行加法以执行MUL,从而使用多个周期。我敢打赌
MUL EAX,3
执行速度比
MOV EBX,EAX SHL EAX,1 ADD EAX,EBX
使用这种优化的最后一个处理器可能是486. (是的,这偏向于Intel处理器,但也可能代表其他体系结构)。
无论如何,任何合理的编译器都应该能够生成最小/最快的代码。因此,始终首先要具有可读性。
回答
不难发现编译器对代码做了什么(我在这里使用的是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在谈论什么,即,编译器足够聪明,可以为代码选择最佳指令。
回答
相信编译器可以优化诸如此类的小段代码。在代码级别,可读性更为重要。真正的优化应该更高层次。
回答
不在乎。我认为还有更多重要的事情需要优化。我们花了多少时间思考和编写该问题,而不是自己进行编码和测试?
:-)
回答
只要我们使用的是不错的优化编译器,只需编写易于编译器理解的代码即可。这使编译器更容易执行聪明的优化。
我们询问此问题表示优化编译器比我们更了解优化。因此,请信任编译器。使用n * 3
。
也看一下这个答案。