2013年4月17日水曜日

CODE COMPLETE 2nd 上でちょっと気になったところ

CODE COMPLETE 第二版の上を読了。ツッコミたい所もそこそこあったりして、そこも含めて完璧な本です。たぶん。2005年の本なので、参考資料は2004年の資料が最後になるのはしょうがないかな……。
参考資料はAmazonで探して、こんな本も買っていますリンクを辿ると良さそうです。

時代に合わないと思った点をひとつだけ。
『階乗やフィボナッチ数列に再帰を使用しない』から。
int Factorial( int number ) {
    if ( number == 1 ) {
        return 1;
    }
    else {
        return number * Factorial( number - 1 );
    }
}
この再帰を使ったルーチンは、実行が低速で実行時に消費されるメモリを予測できないだけでなく、リスト17-9に示す繰り返し構造を使ったルーチンよりも理解するのが難しい。
Code Complete 第二版上,p486-487より引用
 果たして、そうでしょうか。理解するのが難しいという点は、主観的なものだと思う(少なくとも私は難しいと思わない)ので、実行が低速で実行時に消費されるメモリを予測できないという点を考えてみて、Cの二つの処理系で調べてみました。
gcc 4.7.2 (mingw版)で-O2オプション付きでコンパイルした結果
 .file "factorial.c"
 .text
 .p2align 4,,15
 .globl factorial
 .def factorial; .scl 2; .type 32; .endef
 .seh_proc factorial
factorial:
 .seh_endprologue
 movl $1, %eax
 cmpl $1, %ecx
 je .L4
 .p2align 4,,10
.L3:
 imull %ecx, %eax
 subl $1, %ecx
 cmpl $1, %ecx
 jne .L3
 rep
 ret
.L4:
 .p2align 4,,2
 rep
 ret
 .seh_endproc
pcc 1.1.0 (win32版) -O2オプション付きでコンパイルした結果
 .text
 .align 4
 .globl _factorial
_factorial:
 pushl %ebp
 movl %esp,%ebp
 subl $4,%esp
 movl %ebx,-4(%ebp)
L11:
 movl 8(%ebp),%ebx
L13:
 cmpl $1,%ebx
 jne L14
 movl $1,%ebx
 jmp L12
L14:
 leal -1(%ebx),%edx
 pushl %edx
 call _factorial
 addl $4, %esp
 imull %eax,%ebx
L12:
 movl %ebx,%eax
 movl -4(%ebp),%ebx
 leave
 ret
gccの場合、最適化で再帰をループに展開しているので、実行に関してはループで実装した場合と変わらないでしょう。pccの場合、ループに展開されないので、実行にnumber回だけcall/retを含むためにループするよりも遅くなるでしょうし、スタックフレームも作られるため、メモリも消費されるでしょう。
ここから、再帰が遅いかどうかは、言語・処理系(付加するオプション)に依存することが分かります。

0 件のコメント:

コメントを投稿