ということで、ここまでの結果を表にまとめておく。
Pentium4:2.4GHz WindowsXP(MS932) cygwin gcc3.3.1 JDK1.4 |
C | Java | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
最適化 無 | 最適化 有 | インタ プリタ | Hot Spot | AOT | |||||||
malloc | alloca | malloc | alloca | 最適化 無 | 最適化 配列 | 最適化 有 | |||||
行列式 計算 | 再帰 有り | 動的メモリ確保 | 46 | 8 | 43 | 4 | 90 | 9 | 55 | 52 | 49 |
事前メモリ確保 | 5 | 5 | 3 | 3 | 81 | 8 | 10 | 6 | 5 | ||
再帰 無し | 動的メモリ確保 | 44 | 3 | 42 | 3 | 76 | 7 | 52 | 52 | 49 | |
事前メモリ確保 | 3 | 4 | 2 | 2 | 66 | 6 | 7 | 5 | 4 | ||
ループ | 動的メモリ確保 | 46 | - | 44 | - | 154 | 12 | 64 | 52 | 52 | |
事前メモリ確保 | 7 | 7 | 4 | 4 | 159 | 11 | 19 | 8 | 6 |
一応、実行性能の良い順に書くと結果としては以下のようになっている。
「再帰呼び出しを別途の関数に展開」>「再帰呼び出しでの実装」>「再帰呼び出しをループに展開」
別途の関数に展開すると速くなるのが何故なのかは良く分からないが、Javaの実行profileを見る限りでは、何らかの最適化(inline展開など)が行われているためではないかとも思える。
また今回の結果を見る限りでは、単純にループに展開しただけだと速度の向上は無く、むしろ遅くなるという傾向は確かなようだ。
ただ今回の場合、再帰の呼び出し深度は10程度と比較的浅いため、再帰呼び出し自体に性能劣化の要因があるのかどうかは結論できないかも知れない。
ただし再帰の有無は、ソースコードの実行効率を予測する上での判断基準の一つに為り得るという考え方も間違いではない(再帰呼び出しがある場合、無駄なコーディングになっている可能性を検討する方が良い)。
例えば使われている再帰呼び出しが末尾再帰の場合、そのコーディングは本来再帰にする必要のないアルゴリズムであるので、再帰の記述をループに改めるべきであるとは言えるだろう。(ただし、最近のコンパイラは大抵、末尾再帰をループ展開する程度のことはやってくれるらしいので、コーディング段階ではあまり気にする必要もないという意見もある)
今回の場合は末尾再帰ではないので、話はそれ程単純では無かったというだけのことかも知れない。