「たらいまわし関数」というものを知っているだろうか。私は「C言語による最新アルゴリズム辞典」で初めて知った。(もう10年以上も前の話だ。)解説文の中に「特に用途は無い」と書かれているのが気にかかっていた。調べてみると原形は竹内関数というもので、その名が示すとおりに竹内氏が考案したものらしい。しかし、McCarthy氏が誤った形をアメリカで広めてしまい、それと区別するために「たらいまわし関数」と呼ぶようになったという経緯だとのこと。竹内氏はLisp界では名の知れた人でその著書「初めての人のためのLISP」はLisp入門書としては好評なようだ。
で、たらいまわし関数の入出力の関係にはたしかに何の意味もない。意味があるのはその計算量だ。シンプルな定義でありながら、計算量が爆発的に増える。それを利用してベンチマークテストに用いられたりすることもある。もうひとつ、遅延評価の例としてもよく使われる。実際に遅延評価でどの程度の差が出るのか試してみよう。
たらいまわし関数を素直にCで書くと以下のようになる。
/* tarai.c TARAI-function */ #include <stdio.h> int tarai(int x, int y, int z) { if (x <= y) return y; return tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y)); } int main(void) { printf("%d\n", tarai(192, 96, 0)); return 0; }
遅延評価を導入してみよう。Cで書くのは面倒なのでこちらはC++で書くことにする。
/* tarai.cpp TARAI-function (lazy-version) */ #include <iostream> using namespace std; class tarai { const int x, y; const tarai* tp; public: tarai(int y) : x(y), y(y), tp(NULL) {} tarai(int x, int y, const tarai& t) : x(x), y(y), tp(&t) {} operator int() const { return (x <= y) ? y : (int) tarai(tarai(x-1,y,*tp), tarai(y-1,*tp,x), tarai(*tp-1,x,y)); } }; int main(void) { cout << tarai(192, 96, 0); return 0; }
さて、いったいどれくらいの速度差が出るだろうか?手元にC/C++のコンパイラがある人は是非試してみて欲しい。
因みに、計算量が爆発する類似の関数にAckermann関数というのもあるが、これは遅延しても意味がない。
初めての人のためのLISP (ソフトウェアライブラリ (3))
- 作者: 竹内郁雄
- 出版社/メーカー: サイエンス社
- 発売日: 1986/12
- メディア: 単行本
- クリック: 129回
- この商品を含むブログ (9件) を見る
C言語による最新アルゴリズム事典 (ソフトウェアテクノロジー)
- 作者: 奥村晴彦
- 出版社/メーカー: 技術評論社
- 発売日: 1991/03
- メディア: 単行本
- 購入: 19人 クリック: 331回
- この商品を含むブログ (93件) を見る