ねぇもりさん、今日学校で「フィボナッチ数列」を習ったよ
1,1,2,3,5,8って足してくやつ
もり
お~!それじゃあ、フィボナッチ数列をVBAで書いてみよっか!
ほら、このまえ勉強した再帰処理をつかってみよう
【再帰処理をマスターしよう】VBAで階乗の計算をしてみる自身への参照?呼び出す?返る?再帰処理ってむずかしいですよね。VBAで階乗の計算をして、再帰処理をマスターしてみよう!...
もりさん、グイグイくるね。まぁそういうとこキライじゃないよ
あっ、ちなみにひまわりの種の並びはフィボナッチ数列になっているそうですよ。
あとは、松ぼっくりとか、カタツムリの殻とか。
スポンサーリンク
フィボナッチ数列とは?
第1項=1・第2項=1として、【2つ前の数字】と【1つ前の数字】の合計を並べたものです。
1,1,2,3,5,8,13,21,34,55・・・
※ネットで色々みると、フィボナッチ数列の第1項は0と書いてあったり、1と書いてあったりします。
この記事では第1項=1としてプログラムを実装します。
VBAでフィボナッチ数列の第n項を求める
「再帰あり」と「再帰なし」の2パターンで書いてみました。
再帰なしのパターン
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
Sub フィボナッチ数を求める_再帰なし() Dim x As Variant '第n項の2つ前の値 Dim y As Variant '第n項の1つ前の値 x = 1 '第1項の値 y = 1 '第2項の値 '★★★求めたい項を指定★★ Dim n As Long: n = 10 '計算回数をカウント※第1,2項の値はセットしているので、第3項から計算開始 Dim cnt As Long: cnt = 3 Do While cnt <= n Dim total As Variant total = x + y x = y y = total cnt = cnt + 1 Loop '★★★答え★★★ Debug.Print "第" & n & "項→" & total End Sub |
Do~Loop文でやってることはこんな感じです。
桁あふれを考慮して、x,y,totalはVariant型にしています。
第50項だと12,586,269,025になるんですね!
再帰ありのパターン
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Sub フィボナッチ数を求める_再帰あり() '★★★求めたい項を指定★★ Dim n As Long: n = 10 Dim total As Variant total = Fib(n) Debug.Print "第" & n & "項→" & total End Sub Function Fib(n As Long) As Variant If n = 1 Or n = 2 Then Fib = 1 Else Fib = Fib(n - 2) + Fib(n - 1) End If End Function |
Function Fib() が Function Fib()を呼び出していますね。
Fib(10) = Fib(8) + Fib(9)
【2つ前の値】と【1つ前の値】の合計値を求めるので、第10項=第8項+第9項となります。
再帰あり・なしの実行時間を比較してみた
「再帰処理はメモリを食うから遅くなる」といった話を聞いたので、実験してみました。
第20項あたりから差がつくようです。
第n項 | 再帰なし | 再帰あり | 計算結果 |
---|---|---|---|
20 | 0.001~2秒 | 0.004秒 | 6,765 |
25 | 〃 | 0.023秒 | 75,025 |
30 | 〃 | 0.216秒 | 832,040 |
35 | 〃 | 2.29秒 | 9,227,465 |
36 | 〃 | 3.772秒 | 14,930,352 |
37 | 〃 | 6.145秒 | 24,157,817 |
38 | 〃 | 9.934秒 | 39,088,169 |
39 | 〃 | 16.065秒 | 63,245,986 |
40 | 〃 | 26.358秒 | 102,334,155 |
45 | 〃 | 応答なし | 1,134,903,170 |
50 | 〃 | やめておく | 12,586,269,025 |
もり
再帰処理を使わないほうが圧倒的に速いね!
それにしても、これだけの計算を0.001秒でやってのけちゃうVBAってすごいですね!(人間が第50項まで計算するのは大変ですよね)
単純な処理ならば、再帰処理を使わずに、Do~Loop・For~Nextでシンプルに書いたほうがよさそうですね。
スポンサーリンク
スポンサーリンク