みんなが大好きなフィボナッチ
フィボナッチ数列というのは,大抵のプログラムの本,それも再帰を扱っているものなら,まず出ているといってもよいほどの,人気者です.高校の数学の本にもまずでています.出ていなかった,きっと著者がフィボナッチが嫌いか,ウサギが嫌いなのに違いありません.
フィボナッチ数列というのは
という漸化式で表される数列のことで,,,,,・・・のようになります.一般項を求めるのは本筋ではないので割愛します.これをPerlで素直に再帰で書くとこんな感じですね.
sub fib1{ my $n = shift; return 0 if $n==0; return 1 if $n==1; return fib1($n-1)+fib1($n-2); }
プログラムの場合,0から始めるのが多いようなので,0番目から始めることにしています.
ところがこれ,滅茶苦茶に遅くて,ちょっとでも大きい引数を与えるといらいらします.試みになんちゃってベンチマークをしてみます.
sub test{ my ($n, $N, $callback) = @_; my $process_time; for my $i (1..$N){ my $sttime=time; $callback->($n); my $endtime=time; $process_time += $endtime-$sttime; } return $process_time/$N; } print test(10, 1000, \&fib1),"\n";# 第10項を1000回計算して平均を出す print test(20, 1000, \&fib1),"\n";# 第20項を1000回計算して平均を出す
1000回計算させて,平均を出してみると,私の機械だと
0.000156760215759277 0.0192136526107788
実は,30項目を計算させると,一回計算させるだけで2秒を突破します.1000回の平均なんて待ってられません.そこで第5項の計算を書き下してみると
fib(5) -- fib(4) + fib(3) -- fib(2) + 1 | | fib(3) + fib(2) 1 + 1 | | | 1 + 1 fib(2) + 1 | 1 + 1
どんどん枝分かれしていって,すごく早く計算が増えていきます.けど,よくみると同じ計算ばっかりしていることが分かるので,これを排除しようというのがHOPのテクニックです.
と,ここまで書いたんですが・・・haskellでフィボナッチ そしてPerlで書いてみたというページを発見。。。もう一年くらい前に同じことをしてる人がいた.ネタがなくなってしまったような気がしますが,予定通り先に進めようかと思います.