搜索
bottom↓
回复: 38
打印 上一主题 下一主题

for(i=0;i<100;i++)与for(i=100;i>0;i--)相比哪个效率高?

[复制链接]

出5入8汤圆

跳转到指定楼层
1
发表于 2013-11-8 16:51:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
如题,今天进火哥的初学者论坛时有个每日一题,我认为for(i=0;i<100;i++)与for(i=100;i>0;i--)这个两句话的效率是议案的,不过论坛提示我回答错误,求教了度娘,度娘也说是一样的。故来这里请教各位大神这个关于C的问题

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

2
发表于 2013-11-8 16:55:07 来自手机 | 只看该作者
肯定是后面一种效率高

出0入0汤圆

3
发表于 2013-11-8 17:01:54 来自手机 | 只看该作者
后一种,因为为零跳转这条指令jz(?)。
不过没必要纠结哈。

出0入0汤圆

4
发表于 2013-11-8 17:06:48 | 只看该作者
在需要区分for(i=0;i<100;i++)与for(i=100;i>0;i--)哪个效率高的场合,应该使用汇编。

出0入0汤圆

5
发表于 2013-11-8 17:12:12 | 只看该作者
keil 51环境,while(i--);与while(--i);同一个i,执行的时间明显不相等

出0入0汤圆

6
发表于 2013-11-8 17:16:05 | 只看该作者
穷折腾 发表于 2013-11-8 17:06
在需要区分for(i=0;i0;i--)哪个效率高的场合,应该使用汇编。

+1
讓教科書上糾結哪箇效率更高的那個小明去死吧。

出0入0汤圆

7
发表于 2013-11-8 17:23:49 | 只看该作者
如果for循环内不含有使用 i 的其它运算,我相信好的编译器会将 for(i=0;i<100;i++) 或 for(i=100;i>0;i--) 都变成相同的汇编指令。

出0入0汤圆

8
发表于 2013-11-8 17:25:58 | 只看该作者
真没必要纠结这个!

出0入0汤圆

9
发表于 2013-11-8 17:30:12 | 只看该作者
alias 发表于 2013-11-8 17:23
如果for循环内不含有使用 i 的其它运算,我相信好的编译器会将 for(i=0;i0;i--) 都变成相同的汇编指令。 ...

是的,我记得GCC的优化就是会把它变成倒计数的。

出0入0汤圆

10
发表于 2013-11-8 17:38:59 | 只看该作者
第一次发现这个问题涨姿势了

出0入0汤圆

11
发表于 2013-11-8 17:46:02 | 只看该作者
视compiler而定,看你的compiler怎么做。

出0入0汤圆

12
发表于 2013-11-8 17:48:43 | 只看该作者
以前在一些资料上看过,说后面一种写法效率高。

出0入54汤圆

13
发表于 2013-11-8 18:20:34 | 只看该作者
这得看编译器如何做了

出0入0汤圆

14
发表于 2013-11-8 18:52:16 来自手机 | 只看该作者
你要是懂汇编你就知道答案了

出0入0汤圆

15
发表于 2013-11-8 20:29:06 | 只看该作者
和编译器有关系,要看汇编代码。

出0入0汤圆

16
发表于 2013-11-8 20:53:50 | 只看该作者
学习了,以前总是喜欢用i++.

出0入0汤圆

17
发表于 2013-11-8 20:57:18 | 只看该作者
一般来说是后一种,因为比较指令中对于0的判断比较省力,具体是多长的指令,不知道

出0入0汤圆

18
发表于 2013-11-8 21:10:43 | 只看该作者
优化等级开到最高,两者的执行效率如果有区别的话,那么这个编译器毫无疑问是愚蠢的。
优化等级最低的话,应该后者可能会比前者效率更高,原因如楼上所述,大部分单片机机器指令里面判断0都要比判断100效率更高。

出0入0汤圆

19
发表于 2013-11-8 23:36:48 | 只看该作者
do{
}while(--i);

出0入0汤圆

20
发表于 2013-11-9 00:08:58 来自手机 | 只看该作者
个人觉得不仅跟编译器有关,还跟单片机的指令集有关!51单片机,是后者效率高。

出0入0汤圆

21
发表于 2013-11-9 01:24:45 | 只看该作者
不过野火是搞CM3的,不幸的是CM3的测试结果是两者效率一样高。用arm-none-eabi-gcc 4.7.3(launchpad的那个,不是codesourcery)做测试平台。
编译选项
  1. arm-none-eabi-gcc -c -mcpu=cortex-m3 -O0 -gdwarf-2 -mthumb -fomit-frame-pointer -Wall -Wstrict-prototypes -fverbose-asm -Wa,-ahlms=testbench.lst testbench.c -o testbench.o
复制代码
testbench.c内容如下:
  1. #include <stdint.h>
  2. int32_t main(void){
  3.   volatile uint8_t i;
  4.   for(i=0;i<100;i++);
  5.   for(i=100;i>0;i--);
  6.   for(;;);   
  7. }
复制代码
输出的汇编如下:
  1.    3:testbench.c   ****   volatile uint8_t i;
  2.    4:testbench.c   ****   for(i=0;i<100;i++);
  3.   62                              .loc 1 4 0
  4.   63 0002 4FF00003                 mov        r3, #0        @ tmp141,
  5.   64 0006 8DF80730                 strb        r3, [sp, #7]        @ tmp142, i
  6.   65 000a 07E0                     b        .L2        @
  7.   66                      .L3:
  8.   67                              .loc 1 4 0 is_stmt 0 discriminator 2
  9.   68 000c 9DF80730                 ldrb        r3, [sp, #7]        @ tmp144, i
  10.   69 0010 DBB2                     uxtb        r3, r3        @ i.0, tmp144
  11.   70 0012 03F10103                 add        r3, r3, #1        @ tmp145, i.0,
  12.   71 0016 DBB2                     uxtb        r3, r3        @ i.1, tmp145
  13.   72 0018 8DF80730                 strb        r3, [sp, #7]        @ tmp146, i
  14.   73                      .L2:
  15.   74                              .loc 1 4 0 discriminator 1
  16.   75 001c 9DF80730                 ldrb        r3, [sp, #7]        @ tmp148, i
  17.   76 0020 DBB2                     uxtb        r3, r3        @ i.2, tmp148
  18.   77 0022 632B                     cmp        r3, #99        @ i.2,
  19.   78 0024 F2D9                     bls        .L3        @,
  20.    5:testbench.c   ****   for(i=100;i>0;i--);
  21.   79                              .loc 1 5 0 is_stmt 1
  22.   80 0026 4FF06403                 mov        r3, #100        @ tmp149,
  23.   81 002a 8DF80730                 strb        r3, [sp, #7]        @ tmp150, i
  24.   82 002e 07E0                     b        .L4        @
  25.   83                      .L5:
  26.   84                              .loc 1 5 0 is_stmt 0 discriminator 2
  27.   85 0030 9DF80730                 ldrb        r3, [sp, #7]        @ tmp152, i
  28.   86 0034 DBB2                     uxtb        r3, r3        @ i.3, tmp152
  29.   87 0036 03F1FF33                 add        r3, r3, #-1        @ tmp153, i.3,
  30.   88 003a DBB2                     uxtb        r3, r3        @ i.4, tmp153
  31.   89 003c 8DF80730                 strb        r3, [sp, #7]        @ tmp154, i
  32.   90                      .L4:
  33.   91                              .loc 1 5 0 discriminator 1
  34.   92 0040 9DF80730                 ldrb        r3, [sp, #7]        @ tmp156, i
  35.   93 0044 DBB2                     uxtb        r3, r3        @ i.5, tmp156
  36.   94 0046 002B                     cmp        r3, #0        @ i.5,
  37.   95 0048 F2D1                     bne        .L5        @,
  38.   96                      .L6:
复制代码
可见对于CM3平台,即使优先级开到最低,两个代码的执行效率没有分毫的差异。

出0入0汤圆

22
发表于 2013-11-9 02:05:06 | 只看该作者
对51来说,由于DJNZ等指令的存在,i--通常会更快一些。
对RISC处理器,如ARM,通常不会编码DJNZ这样的复合操作指令,因而二者效率不会有什么差异。
x86系统忘记了,不过CMP + JNZ两条指令可以融合,执行的时候不用那么多周期。

出0入0汤圆

23
发表于 2013-11-9 08:57:35 | 只看该作者
这下长知识了,我也不知道

出0入8汤圆

24
发表于 2013-11-9 09:13:15 来自手机 | 只看该作者
不说内核和编译器,出这题没有任何意义。

出0入0汤圆

25
发表于 2013-11-9 09:39:38 | 只看该作者
对于51 ,后者效率高些

出0入0汤圆

26
发表于 2013-11-9 10:18:51 | 只看该作者
schwarz 发表于 2013-11-9 01:24
不过野火是搞CM3的,不幸的是CM3的测试结果是两者效率一样高。用arm-none-eabi-gcc 4.7.3(launchpad的那个 ...

你这个测试不完善,忽视了一个问题,

77 0022 632B                     cmp        r3, #99        @ i.2,

立即数99因为不够大、不够随机,所以是能够被硬编码进汇编指令的。否则的话,在这之前是需要添加加载指令的。

出5入8汤圆

27
 楼主| 发表于 2013-11-9 11:40:09 | 只看该作者
superAFE 发表于 2013-11-8 17:44
学了一也孔乙己研究一下茴香豆的“茴”字的写法。。

是后面一种效率高,在KEIL的默认等级中,后面的采用DJ ...

涨知识了,多谢

出5入8汤圆

28
 楼主| 发表于 2013-11-9 11:41:50 | 只看该作者
Wxy8030 发表于 2013-11-8 17:25
真没必要纠结这个!

仅仅是学习的,要不是突然看到这个问题,我一直认为是这个两句话没有区别,呵呵,学习一下

出5入8汤圆

29
 楼主| 发表于 2013-11-9 11:43:17 | 只看该作者
WANG_JINLONG 发表于 2013-11-8 18:52
你要是懂汇编你就知道答案了

很尴尬,不懂汇编

出0入0汤圆

30
发表于 2013-11-9 13:19:01 来自手机 | 只看该作者
不要纠结在这个问题上!!!

出5入8汤圆

31
 楼主| 发表于 2013-11-9 15:55:00 | 只看该作者
tsb0574 发表于 2013-11-9 13:19
不要纠结在这个问题上!!!

恩恩

出0入0汤圆

32
发表于 2013-11-9 16:37:16 | 只看该作者
在初学51时看到过相关资料,说后一种的效率高一点,写程序时尽量采用这种结构.

出0入0汤圆

33
发表于 2013-11-9 19:27:01 | 只看该作者
继续测试22楼代码,这次使用的编译器是mingw 4.7.2 32bit
编译选项:
  1. gcc -O0 -Wall -Wstrict-prototypes -Wa,-ahlms=testbench.lst testbench.c -o testbench.o
复制代码
代码如下,两者执行速度并无差异
  1.   12 000e C644240F                 movb        $0, 15(%esp)
  2.   12      00
  3.   13 0013 EB09                     jmp        L2
  4.   14                      L3:
  5.   15 0015 8A44240F                 movb        15(%esp), %al
  6.   16 0019 40                       incl        %eax
  7.   17 001a 8844240F                 movb        %al, 15(%esp)
  8.   18                      L2:
  9.   19 001e 8A44240F                 movb        15(%esp), %al
  10.   20 0022 3C63                     cmpb        $99, %al
  11.   21 0024 76EF                     jbe        L3
  12.   22 0026 C644240F                 movb        $100, 15(%esp)
  13.   22      64
  14.   23 002b EB09                     jmp        L4
  15.   24                      L5:
  16.   25 002d 8A44240F                 movb        15(%esp), %al
  17.   26 0031 48                       decl        %eax
  18.   27 0032 8844240F                 movb        %al, 15(%esp)
  19.   28                      L4:
  20.   29 0036 8A44240F                 movb        15(%esp), %al
  21.   30 003a 84C0                     testb        %al, %al
  22.   31 003c 75EF                     jne        L5
复制代码
然后将优化选项-O0变成-O3 -Os为了执行速度最大优化,代码同上。

出0入0汤圆

34
发表于 2013-11-9 20:23:43 | 只看该作者
这次用Microchip XC8 v1.12测试,编译选项如下:
  1. D:\eda\Microchip\xc8\v1.12\bin\xc8.exe" --pass1  --chip=16F877A -Q -G --asmlist  --double=24 --float=24 --opt=default,+asm,+asmfile,+speed,-space,-debug --addrqual=ignore --mode=pro -N31 --warn=0 --summary=default,-psect,-class,+mem,-hex,-file --output=default,-inhx032 --runtime=default,+clear,+init,-keep,-no_startup,+osccal,-resetbits,-download,-stackcall,+clib "--errformat=%%f:%%l: error: %%s" "--warnformat=%%f:%%l: warning: %%s" "--msgformat=%%f:%%l: advisory: %%s"  -obuild/default/production/main.p1  main.c
复制代码
出来的汇编代码如下:
  1.    292                           ;main.c: 54: volatile uint8_t i;
  2.    293                           ;main.c: 55: for(i=0;i<100;i++);
  3.    294  0432  01FC                       clrf        main@i        ;volatile
  4.    295  0433                     l670:       
  5.    296  0433  3064                       movlw        100
  6.    297  0434  027C                       subwf        main@i,w        ;volatile
  7.    298  0435  1803                       btfsc        3,0
  8.    299  0436  2C39                       goto        l678
  9.    300  0437  0AFC                       incf        main@i,f        ;volatile
  10.    301  0438  2C33                       goto        l670
  11.    302  0439                     l678:       
  12.    303                           
  13.    304                           ;main.c: 56: for(i=100;i>0;i--);
  14.    305  0439  3064                       movlw        100
  15.    306  043A  00FC                       movwf        main@i        ;volatile
  16.    307  043B  08FC                       movf        main@i,f
  17.    308  043C  1903                       btfsc        3,2
  18.    309  043D  2C40                       goto        l686
  19.    310  043E                     l684:       
  20.    311  043E  0BFC                       decfsz        main@i,f        ;volatile
  21.    312  043F  2C3E                       goto        l684
  22.    313  0440                     l686:       
复制代码
很明显后者的执行速度要比前者快得多。
不做别的测试了,测试了arm和x86平台的gcc,结论是两个语句执行速度一样。而在Microchip的8位单片机编译平台后者比前者快。

出0入0汤圆

35
发表于 2013-11-9 20:26:21 | 只看该作者
···感觉纠结这种问题···没有多大的意义,有这个时间和精力,不如去学一点高级的算法···

出0入0汤圆

36
发表于 2013-11-9 20:32:38 | 只看该作者
schwarz 发表于 2013-11-9 01:24
不过野火是搞CM3的,不幸的是CM3的测试结果是两者效率一样高。用arm-none-eabi-gcc 4.7.3(launchpad的那个 ...

我记得cm3有czb和cznb指令,就是判0和跳转,可以合并比较和跳转2条指令

出0入0汤圆

37
发表于 2013-11-9 20:35:43 | 只看该作者
前一种效率高。

出5入8汤圆

38
 楼主| 发表于 2013-11-9 21:32:48 | 只看该作者
lanzhe1991 发表于 2013-11-9 20:35
前一种效率高。

汇编指令,只有 与 0 比较大小,没有直接与 100 比较大小

i<100  等效为 i - 100 < 0
相比 i > 0 ,多了一步减法 ,因而效率更低。

正确答案为 B。

注:有的 编译器 开优化功能后,有可能 使得两者差别不大,但也是 后者 更有效。

火哥给的解释哦

出5入8汤圆

39
 楼主| 发表于 2013-11-9 21:33:38 | 只看该作者
woshiqinyikun 发表于 2013-11-9 20:26
···感觉纠结这种问题···没有多大的意义,有这个时间和精力,不如去学一点高级的算法··· ...

恩恩  只是探讨一下而已
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 16:25

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表