竹内関数

竹内関数（たけうちかんすう）は、プログラミング言語処理系のベンチマークなどに使われる、再帰的に定義された関数である。

 概要 
再帰的に定義される、3個の引数 x, y, z をとる次のような関数である。

特に変わる所は無いがLisp版https://www.nue.org/nue/index.html#tak-function 2023年9月1日閲覧。も参照のこと。定義からわかるように処理を次々にたらい回しにしていくことから、たらいまわし関数、たらい関数 (Tarai function) とも呼ばれる（後述のマッカーシー版との混同を避けるためこの名で呼ばれることのほうが多いが、こちらの定義のほうがオリジナルである。マッカーシー版を特にTak関数として区別する場合もある）。電電公社研究員（当時）の竹内郁雄が、1974年の夏前の頃、後述するような特性のある関数をあれこれ考えていた、ある日の午前に思いついたものである。竹内関数と命名したのは野崎昭弘である。

特性として、よくベンチマークに使われる関数であるフィボナッチ数を何の工夫もなく計算するいわゆるダム（dumb）フィボナッチと比較して、大きな数の計算が必要ない（ワード長の整数演算さえ実装していれば十分）、再帰が深くならない（大きな量のスタックを使えなくても十分）といったものがある。このためベンチマークとしてはその処理系の関数呼び出し（と戻り）のオーバーヘッドの寄与度が大きい結果が計算でき、メモリの少ないハードウェアや多倍長計算が無い処理系などのような制限の大きい環境でも実装し測定できるといった特徴がある。

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

計算量はずっと少ない（たとえば tarai(12, 6, 0) では 12,604,860 回 tarai が呼ばれるのに対し、 tak(12, 6, 0) では tak は 63,608 回しか呼ばれない）。

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

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

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

 メモ化
 一度計算した値を覚えておき、次の呼び出しではその値を使う。
 遅延評価
 クロージャなどを利用して、関数呼び出しの計算より前に引数を計算すること（先行評価）をしない（ただし、クロージャ生成のコストがかかる）。原則として遅延評価する言語であるHaskellでは定義そのままで非常に速い。他にもScalaなど遅延評価に対応した言語においては、簡単に、非常に高速に評価が終わるコードを作成できる。

マッカーシー版は、メモ化では同様に速い。しかし、マッカーシー版をHaskellなどでそのままの定義で遅延評価した場合は、高速にならない（遅延評価では計算量が減らない）、という違いがある。これは少し動作を追いかけて考えてみるとわかるが、本物では z の値をたらいまわしした挙句に結局使っていない（捨ててしまっている）ため、遅延評価ではその計算がごっそり行われなくなるからである。マッカーシー版では z を返しているため結局その値が必要になっている、という違いになっている。先行評価による tarai(n, 0, n+1) の計算全体において「さもなくば」の側が評価される回数をTakeuchi Numberと言う。

 感覚化 
数値データ等を視覚や聴覚でとらえられるようにすることがあるが（視覚の場合可視化という）、竹内関数の引数の値に音階を割り振り、3個の引数で和音のような音にした試みがある。

 参照 

 関連項目 
 アッカーマン関数

 外部リンク 
 Wolfram MathWorld

Category:特殊関数
Category:計算理論
Category:数学に関する記事