C言語のwhileとdo-whileに速度の違いはあるのか。
友人に whileとdo-whileに速度の違いはあるのか? というような質問をされました。 考えたこともなかったので、ちょっと色々やってみました。
とりあえず書いてみたコードがこれ。
#include <stdio.h>
int main(){
int i=0;
while(i<1000000000){
i++;
}
return 0;
}
これがwhile版。
#include <stdio.h>
int main(){
int i=0;
do{
i++;
}while(i<1000000000);
return 0;
}
こっちがdo-while版。 どちらもほぼ同じで、10億回ループするだけのコードです。
で、GCCでアセンブリにしてみる。
$ gcc -O0 -S while.c
コマンドはこんな感じ。
まずはwhile版。
.file "while.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $0, -4(%rbp)
jmp .L2
.L3:
addl $1, -4(%rbp)
.L2:
cmpl $999999999, -4(%rbp)
jle .L3
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Gentoo 4.8.4 p1.5, pie-0.6.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
ラベル2つも使うんですね。おもしろい。
で、do-while版がこちら。
.file "do-while.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $0, -4(%rbp)
.L2:
addl $1, -4(%rbp)
cmpl $999999999, -4(%rbp)
jle .L2
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Gentoo 4.8.4 p1.5, pie-0.6.1) 4.8.4"
.section .note.GNU-stack,"",@progbits
お、ラベルが少ない。 ぱっと見こちらの方がシンプルな仕上がりになっています。行数も少ないし。
なるほど、do-whileの方が速いんだね。・・・とは言い難いので、実測値。 timeコマンドのuserの値を5つ。
while [秒] | do-while [秒] | |
---|---|---|
1回目 | 1.603 | 1.601 |
2回目 | 1.597 | 1.609 |
3回目 | 1.611 | 1.597 |
4回目 | 1.608 | 1.597 |
5回目 | 1.606 | 1.604 |
平均 | 1.615 | 1.602 |
・・・うーん。
結論: whileとかdo-whileとかどっちでもいいから、効率的なアルゴリズムを考えなさい。