再帰プログラミング
コード① - なりに書いてみる
object Fibonacci { def main(args: Array[String]): Unit = { printExecutionTime(println(fibo(100))) } def fibo(n: Int): Int = n match { case 1 => 1 case 2 => 1 case n => fibo(n - 2) + fibo(n - 1) } def printExecutionTime(proc: => Unit) = { val start = System.currentTimeMillis proc println((System.currentTimeMillis - start) + "msec") } }
実行結果①
かえってこない(笑)
Σヽ(゚Д゚; )ノ アッ となりました。そりゃ、そうだ。オーダーもフィボナッチ数列になるんだもの。
コード② - 末尾再帰にする
object Fibonacci { def main(args: Array[String]): Unit = { printExecutionTime(println(fibo(100))) } def fibo(n: Int): Int = { def fibo2(a: Int, b: Int, count: Int): Int = count match { case 0 => a case 1 => b case count => fibo2(b, a + b, count - 1) } fibo2(1, 1, n) } def printExecutionTime(proc: => Unit) = { val start = System.currentTimeMillis proc println((System.currentTimeMillis - start) + "msec") } }
実行結果②
-1869596475 228msec
結果は出たが、、、うん。
コード③ - Long にする
object Fibonacci { def main(args: Array[String]): Unit = { printExecutionTime(println(fibo(100))) } def fibo(n: Int): Long = { def fibo2(a: Long, b: Long, count: Int): Long = count match { case 0 => a case 1 => b case count => fibo2(b, a + b, count - 1) } fibo2(1, 1, n) } def printExecutionTime(proc: => Unit) = { val start = System.currentTimeMillis proc println((System.currentTimeMillis - start) + "msec") } }
実行結果③
1298777728820984005 262msec
やっと出ました。長い道のりでしたが、勉強になりました。
末尾再帰になっているかチェックするアノテーション
@tailrec
アノテーションをつけると、末尾再帰になっているかどうかをコンパイルのタイミングでチェックしてくれます。
@tailrec def fibo(n: Int): Int = n match { case 1 => 1 case 2 => 1 case n => fibo(n - 2) + fibo(n - 1) }
とするとコンパイルのときに怒られます。
Error:(16, 27) could not optimize @tailrec annotated method fibo: it contains a recursive call not in tail position case n => fibo(n - 2) + fibo(n - 1)