「竹内関数」の版間の差分

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
USAGI-WRP (会話 | 投稿記録)
→‎高速化: Scalaでも遅延評価関数で書けばネイティブには適いませんが同様に高速化できます
編集の要約なし
1行目: 1行目:
'''竹内関数'''(たけうちかんすう)とは三つの[[整数]] ''x, y, z'' に対して、次のように再帰的に[[定義]]される[[関数 (数学)|関数]]である。
'''竹内関数'''(たけうちかんすう)とは三つの[[整数]] ''x, y, z'' に対して、次のように再帰的に[[定義]]される[[関数 (数学)|関数]]である。


<math>{\rm Tak}(x, y, z) = \begin{cases}
<math>{\rm Tarai}(x, y, z) = \begin{cases}
y & \mbox{ if }x \le y\\
y & \mbox{ if }x \le y\\
{\rm Tak}({\rm Tak}(x - 1, y, z), {\rm Tak}(y - 1, z, x), {\rm Tak}(z - 1, x, y)) & \mbox{ otherwise. }\\
{\rm Tarai}({\rm Tarai}(x - 1, y, z), {\rm Tarai}(y - 1, z, x), {\rm Tarai}(z - 1, x, y)) & \mbox{ otherwise. }\\
\end{cases}</math>
\end{cases}</math>


定義からわかるように処理を次々にたらいまわしにしていくことから、'''[[たらい回し|たらいまわし]]関数、[[たらい]]関数'''(''Tarai function'')とも呼ばれる(後述のマッカーシー版との混同を避けるためこの名で呼ばれることのほうが多いが、こちらの定義のほうがオリジナルである)。[[日本電信電話公社|電電公社]]研究員(当時)の[[竹内郁雄]]が[[1976年]]に考案した。与える数によって関数の再帰呼び出しの回数が非常に増え、計算量が大きくなるため、コンピュータの[[ベンチマーク|性能測定]]などに用いられる。
定義からわかるように処理を次々にたらいまわしにしていくことから、'''[[たらい回し|たらいまわし]]関数、[[たらい]]関数'''(''Tarai function'')とも呼ばれる(後述のマッカーシー版との混同を避けるためこの名で呼ばれることのほうが多いが、こちらの定義のほうがオリジナルである。マッカーシー版を特にTak関数として区別する場合もある)。[[日本電信電話公社|電電公社]]研究員(当時)の[[竹内郁雄]]が[[1976年]]に考案した。与える数によって関数の再帰呼び出しの回数が非常に増え、計算量が大きくなるため、コンピュータの[[ベンチマーク|性能測定]]などに用いられる。


== マッカーシー版 ==
== マッカーシー版 ==
15行目: 15行目:
{\rm Tak}({\rm Tak}(x - 1, y, z), {\rm Tak}(y - 1, z, x), {\rm Tak}(z - 1, x, y)) & \mbox{ otherwise. }\\
{\rm Tak}({\rm Tak}(x - 1, y, z), {\rm Tak}(y - 1, z, x), {\rm Tak}(z - 1, x, y)) & \mbox{ otherwise. }\\
\end{cases}</math>
\end{cases}</math>

計算量はずっと少ない。


== 本質 ==
== 本質 ==
竹内関数の出力は以下のものと同等である。
竹内関数の出力は以下のものと同等である。


<math>{\rm Tak0}(x, y, z) = \begin{cases}
<math>{\rm T0}(x, y, z) = \begin{cases}
y & \mbox{ if }x \le y\\
y & \mbox{ if }x \le y\\
z & \mbox{ if }x > y \mbox { and } y \le z\\
z & \mbox{ if }x > y \mbox { and } y \le z\\
x & \mbox{ otherwise. }\\
x & \mbox{ otherwise. }\\
\end{cases}</math>
\end{cases}</math>

[[ドナルド・クヌース]]による研究が、Textbook Examples of Recursion(1990)にある。


== 高速化 ==
== 高速化 ==
竹内関数を高速化するには関数の再帰呼び出しのコストを小さくする必要がある。これには次のような手法がある。
竹内関数を高速化するには関数呼び出しのコストを小さくする、というまっとうな手法と、計算を必要になるまでやらない(引数のx, y, zの値実際に必要なのは、関数の呼び出し時でなくifの評価時である)か、一度やった計算の結果を再利用するかして、計算量自体を削減する(当然非常に速いベンチマークとしては一種のチートと言えなくもない)手法とがあり、後者には次のような手法がある。


* [[メモ化]]
* [[メモ化]]

2010年4月4日 (日) 09:47時点における版

竹内関数(たけうちかんすう)とは三つの整数 x, y, z に対して、次のように再帰的に定義される関数である。

定義からわかるように処理を次々にたらいまわしにしていくことから、たらいまわし関数、たらい関数(Tarai function)とも呼ばれる(後述のマッカーシー版との混同を避けるためこの名で呼ばれることのほうが多いが、こちらの定義のほうがオリジナルである。マッカーシー版を特にTak関数として区別する場合もある)。電電公社研究員(当時)の竹内郁雄1976年に考案した。与える数によって関数の再帰呼び出しの回数が非常に増え、計算量が大きくなるため、コンピュータの性能測定などに用いられる。

マッカーシー版

ジョン・マッカーシーは竹内関数を記憶違いで[1] z を返すように変更し、これがTak関数として広まった。以下がその定義である。

計算量はずっと少ない。

本質

竹内関数の出力は以下のものと同等である。

ドナルド・クヌースによる研究が、Textbook Examples of Recursion(1990)にある。

高速化

竹内関数を高速化するには、関数呼び出しのコストを小さくする、というまっとうな手法と、計算を必要になるまでやらない(引数のx, y, zの値が実際に必要なのは、関数の呼び出し時でなくifの評価時である)か、一度やった計算の結果を再利用するかして、計算量自体を削減する(当然非常に速い。ベンチマークとしては一種のチートと言えなくもない)手法とがあり、後者には次のような手法がある。

一度計算した値を覚えておき、次の呼び出しではその値を使う。

クロージャなどを利用してその場では関数を計算しない(ただし、クロージャ生成のコストがかかる)。原則として遅延評価する言語であるHaskellでは定義そのままで非常に速い。他にもScalaなど遅延評価に対応した言語においては非常に高速なコードを記述、実行する事ができる。

参照

  1. ^ どう転んでもLisp - スライド12

関連項目

外部リンク