原标题:编程实现从 1 加到 100 和从 100 加到 1 两个程序,哪个更快?为什么?
这是一个非常有趣的问题——而且也一直以来都很有争论。
认为“100加到1比1加到100”快的人,往往是基于这样一个事实:
jnz指令要明显快于cmp之后再jne
但是,这里有一个问题:编译器是否真的会把循环中的“不等于零”用nz指令来替换?
这里以C语言为实验对象。
好的,我现在在wsl上运行了gcc (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0
然后,用下面这段程序作为例子。
int sum;
int i;
int main(){
sum=0;
for(i=100;i!=0;i--)
sum+=i;
return 0;}
一个很简单的C程序。
我们用gcc来进行一下汇编。
gcc -O0 -S 1.c
好的,我猜不会有多少人愿意看……那就摘一下重点吧。
比较的地方的汇编如下:
movl i(%rip), %eax
testl %eax, %eax
jne .L3
而对于“从1加到100”而言,这一段则是
movl i(%rip), %eax
cmpl $100, %eax
jle .L3
并没有本质的区别。
为了保险起见,我们把循环中的
for(i=100;i!=0;i--)
改成
for(i=101;--i;)
于是,对比输出的汇编结果,除了循环体内的减法操作跑到了比较的地方之外,并没有更多的差别。
那么,如果打开/O1呢…会不会把nz这种东西优化进来
movl $5050, sum(%rip)
当我没说…
于是现在,我们使用msvc试一试。(19.16.27030.1)
cl /Od /FAs /c /Fonul 1.c
和刚才类似地,对于一路减下去的做法,汇编里依然多了个cmp指令
cmp DWORD PTR i, 0
je SHORT $LN3@main
而,如果是一路加上来,比较也并不会复杂很多
cmp DWORD PTR i, 100 ; 00000064H
jg SHORT $LN3@main
至于那种非要把--i放到循环条件里的…enmmm…您别说,还真的少了一行汇编…
我找了半天才看出来差在哪…
别人是先jmp到循环条件那里检查一下…不知道为啥,到了这里就是一个大循环…
不过…要执行上千行汇编的事…您给我说这一行jmp…不太好吧…
好的,看到有人说到了“上古时代”的编译器会有这种特性。
于是在DOSBOX中运行Turbo C 1.0进行实验。
TCC -S 1.c
一如既往,同样的行数,同样的快乐。
cmp word ptr dgroup:_i,0
jne @4
cmp word ptr dgroup:_i,100
jle @4
然而,在最后一种“奇葩”方法的测试中,我们终于如愿以偿收获了惊喜。
dec word ptr dgroup:_i
jne @4
在循环体内,确实就像想象的那样,少了一个cmp指令。
不过先不要急着下结论。我们继续我们的实验。
这次我们用刚刚下载的icc来测试(Version 19.0.3.203 Build 20190206)
test eax, eax ;5.15
je .B1.4 ; Prob 50% ;5.15
cmp eax, 100 ;5.13
jg .B1.4 ; Prob 50% ;5.13
而--i的做法这次…
我看了好半天…有点没看明白为什么会出现这种智障操作…
mov DWORD PTR [rbp], eax ;5.14
mov eax, DWORD PTR [rbp] ;5.14
mov DWORD PTR [i], eax ;5.14
mov eax, DWORD PTR [rbp] ;5.14
不过从结果上来看…它每次循环比另外两种写法要多执行两条语句…
以后我想做一下其它语言和编译器的测试
不过就目前的结果来看…
这名学生完全可以问面试官具体的架构环境编译器参数…
嗯,如果面试官认为没开优化的编译器都可以…那么…
“老师,您预习编译原理了吗?”返回搜狐,查看更多
责任编辑: