わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

Re: 関数の呼び出し回数

「課題のプログラムを実行するときに,fib(40)は何回呼び出しますか? fib(39)は何回呼び出しますか? …というように,引数ごとにfibの呼び出し回数を分けると,どうなるでしょうね?」
(略)
「さっき言った,fibの各引数を何回呼び出すかってのを,fibに与える初期値ごとに求めると,面白い性質が出てくるんだけどね」
「えっとどういうことでしょうか?」
「2重ループを作ってください」

関数の呼び出し回数 - わさっき

求めてみました.Cのコードがちょっと楽しかったのですが,諸事情によりC版は公開せず,Rubyワンライナーを作りました.
まずはフィボナッチ数を求めるところから.

$ ruby -e 'def fib(n) n<=2?1:fib(n-1)+fib(n-2) end;puts fib(40)'

しばらく待っても,答えが返ってきません*1.数値を減らします.

$ ruby -e 'def fib(n) n<=2?1:fib(n-1)+fib(n-2) end;puts fib(20)'
6765
$ ruby -e 'def fib(n) n<=2?1:fib(n-1)+fib(n-2) end;puts fib(30)'
832040

そうしていると,fib(40)の結果も出ました.102334155で,Cのと同じです.
小さいのから順に,フィボナッチ数を出力させましょう.

$ ruby -e 'def fib(n) n<=2?1:fib(n-1)+fib(n-2) end;1.upto(20){|i|puts fib(i)}'

1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040

『fibの各引数を何回呼び出すかってのを,fibに与える初期値ごとに求める』ための処理を,付け加えます.

$ ruby -e 'def fib(n,a) a[n-1]+=1;n<=2?1:fib(n-1,a)+fib(n-2,a) end;1.upto(30){|i|a=[0]*i;puts fib(i,a);a.size.times{|j|puts " fib(#{j+1}):#{a[j]}"}}'

メソッドfibを2引数にしました.fibの第1引数は1オリジン,配列aは0オリジンです.
出力は長くなるので,fib(30)の呼び出し分だけを.

832040
  fib(1):317811
  fib(2):514229
  fib(3):317811
  fib(4):196418
  fib(5):121393
  fib(6):75025
  fib(7):46368
  fib(8):28657
  fib(9):17711
  fib(10):10946
  fib(11):6765
  fib(12):4181
  fib(13):2584
  fib(14):1597
  fib(15):987
  fib(16):610
  fib(17):377
  fib(18):233
  fib(19):144
  fib(20):89
  fib(21):55
  fib(22):34
  fib(23):21
  fib(24):13
  fib(25):8
  fib(26):5
  fib(27):3
  fib(28):2
  fib(29):1
  fib(30):1

最終行の「fib(30):1」は,最初のワンライナーでfib(30)を計算する際,fib(30)はちょうど1回呼び出したことを表します.その20行前の「fib(10):10946」は,fib(30)を計算するためにfib(10)をその回数呼び出したということです.
他の値も見ると,x≧2のとき,fib(x)を計算する際の「fib(x)の呼び出し回数」「fib(x-1)の呼び出し回数」「fib(x-2)の呼び出し回数」…「fib(2)の呼び出し回数」がフィボナッチ数になっていることが分かります.fib(1)の呼び出し回数は,fib(3)のそれと一致します.
さらに,「fib(1)の呼び出し回数」と「fib(2)の呼び出し回数」の和は,fib(x)と等しくなります.これは,fib(x)を求めるにあたり「+1」されるのが,fib(1)かfib(2)を呼び出したときに限られるからですね.

*1:Rubyらしいコードで,かつ効率良く計算するなら,フィボナッチ数列、今日も - rubyco(るびこ)の日記ですね.