「末尾再帰最適化」の版間の差分

提供: MonoBook
ナビゲーションに移動 検索に移動
1行目: 1行目:
 
'''末尾再帰最適化'''(まつびさいきさいてきか)とは、賢い[[コンパイラ]]が[[末尾再帰]]を検出すると、[[最適化]]時に[[再帰]]を展開し、消し去ってくれる機能のことである。
 
'''末尾再帰最適化'''(まつびさいきさいてきか)とは、賢い[[コンパイラ]]が[[末尾再帰]]を検出すると、[[最適化]]時に[[再帰]]を展開し、消し去ってくれる機能のことである。
 +
 +
[[末尾呼び出し最適化]]([[Tail Call Optimization]]、[[TCO]])の一種で、[[再帰]]だとその効果が絶大だという話であり、やっていることは同じである。
  
 
[[末尾再帰]]であれば後に続く処理はないので、途中経過を保持する[[変数]]と、[[プログラマー]]が手で書くとボロクソに言われる[[goto文]]や[[アセンブリ言語]]のjmp命令などを用いて、[[再帰]]を無くす(展開する)ことができる。
 
[[末尾再帰]]であれば後に続く処理はないので、途中経過を保持する[[変数]]と、[[プログラマー]]が手で書くとボロクソに言われる[[goto文]]や[[アセンブリ言語]]のjmp命令などを用いて、[[再帰]]を無くす(展開する)ことができる。
5行目: 7行目:
 
末尾再帰最適化はこの[[末尾再帰]]の特性を利用し、[[再帰]]は[[リソース]]馬鹿食いで[[スタックオーバーフロー]]の危険性があり、何よりクソ重い、かといって[[プログラマー]]が手動で[[再帰]]を展開しておくと9割方[[ソースコード]]がクソ読みにくくなる、という問題を[[コンパイラ]]による[[最適化]]時に半自動で解決してくれる優れものである。
 
末尾再帰最適化はこの[[末尾再帰]]の特性を利用し、[[再帰]]は[[リソース]]馬鹿食いで[[スタックオーバーフロー]]の危険性があり、何よりクソ重い、かといって[[プログラマー]]が手動で[[再帰]]を展開しておくと9割方[[ソースコード]]がクソ読みにくくなる、という問題を[[コンパイラ]]による[[最適化]]時に半自動で解決してくれる優れものである。
  
ただし、[[末尾再帰最適化]]が行われるかは[[コンパイラ]]の気分次第であり、どうなるかわからない諸刃の剣。たとえば[[C Sharp|C#]]であれば、[[マイクロソフト]]製の[[コンパイラ]]で、ターゲットが[[x64]]、かつリリースビルド(最適化が有効な状態)でのみ末尾再帰最適化が行われる。つまりデフォルトでは最適化が無効となっているデバッグビルド時には末尾最適化が行われないという。
+
== 末尾再帰最適化に対応した主なプログラミング言語 ==
 +
[[末尾再帰最適化]]が行われるかは[[コンパイラ]]の気分次第であり、どうなるかわからない諸刃の剣。
 +
 
 +
=== C# ===
 +
[[C Sharp|C#]]では、[[マイクロソフト]]製の[[コンパイラ]]で、ターゲットが[[x64]]、かつリリースビルド(最適化が有効な状態)でのみ末尾再帰最適化が行われる。つまりデフォルトでは最適化が無効となっているデバッグビルド時には末尾最適化が行われないという。
 +
 
 +
[[Mono]]での結果については未調査。
 +
 
 +
=== Python ===
 +
[[Python]]ではPython 2.4から導入された[[デコレーター]]を用いて、[[関数]]の頭に「@tail_recursive」と書くことで末尾再帰最適化を明示することができる。
 +
 
 +
[[階乗]](factorial)の記述例。
 +
<source lang="python">
 +
@tail_recursive
 +
def fact(n, acc = 1):
 +
    return acc if n == 0 else fact(n - 1, n * acc)
 +
</source>
 +
 
 +
[[フィボナッチ数]](fibonacci)の記述例。
 +
<source lang="python">
 +
def fib(n):
 +
    @tail_recursive
 +
    def fib_iter(a, b, m):
 +
        return a if m == 0 else fib_iter(b, a + b, m - 1)
 +
    return fib_iter(0, 1, n)
 +
</source>
  
 
== 関連項目 ==
 
== 関連項目 ==
 +
* [[再帰]]
 
* [[末尾再帰]]
 
* [[末尾再帰]]
* [[再帰]]
 
 
* [[最適化]]
 
* [[最適化]]
 +
* [[末尾呼び出し最適化]]
  
 
== 参考文献 ==
 
== 参考文献 ==

2012年5月2日 (水) 05:20時点における版

末尾再帰最適化(まつびさいきさいてきか)とは、賢いコンパイラ末尾再帰を検出すると、最適化時に再帰を展開し、消し去ってくれる機能のことである。

末尾呼び出し最適化Tail Call OptimizationTCO)の一種で、再帰だとその効果が絶大だという話であり、やっていることは同じである。

末尾再帰であれば後に続く処理はないので、途中経過を保持する変数と、プログラマーが手で書くとボロクソに言われるgoto文アセンブリ言語のjmp命令などを用いて、再帰を無くす(展開する)ことができる。

末尾再帰最適化はこの末尾再帰の特性を利用し、再帰リソース馬鹿食いでスタックオーバーフローの危険性があり、何よりクソ重い、かといってプログラマーが手動で再帰を展開しておくと9割方ソースコードがクソ読みにくくなる、という問題をコンパイラによる最適化時に半自動で解決してくれる優れものである。

末尾再帰最適化に対応した主なプログラミング言語

末尾再帰最適化が行われるかはコンパイラの気分次第であり、どうなるかわからない諸刃の剣。

C#

C#では、マイクロソフト製のコンパイラで、ターゲットがx64、かつリリースビルド(最適化が有効な状態)でのみ末尾再帰最適化が行われる。つまりデフォルトでは最適化が無効となっているデバッグビルド時には末尾最適化が行われないという。

Monoでの結果については未調査。

Python

PythonではPython 2.4から導入されたデコレーターを用いて、関数の頭に「@tail_recursive」と書くことで末尾再帰最適化を明示することができる。

階乗(factorial)の記述例。

@tail_recursive 
def fact(n, acc = 1):
    return acc if n == 0 else fact(n - 1, n * acc)

フィボナッチ数(fibonacci)の記述例。

def fib(n):
    @tail_recursive
    def fib_iter(a, b, m):
        return a if m == 0 else fib_iter(b, a + b, m - 1)
    return fib_iter(0, 1, n)

関連項目

参考文献


外部リンク