FRACTRAN

FRACTRAN（フラクトラン）はチューリング完全な難解プログラミング言語で、数学者ジョン・コンウェイによって開発された。この言語で書かれたプログラムは、正の整数nを初期値として持つ正の分数の列である。プログラムは、以下のように整数nを更新することによって実行される。

 nfが整数となるようなリスト内の最初の分数fにおいて、nをnfに置換する。
 nをかけて整数となるような分数がリスト内になくなるまでこれを繰り返し、停止する。

には、PRIMEGAME（素数ゲーム）と呼ばれる、連続する素数を探索する以下のFRACTRANプログラムがある。n=2として始め、このFRACTRANプログラムは以下の整数列を生成する。
 2, 15, 825, 725, 1925, 2275, 425, 390, 330, 290, 770, ... （）

2の後、この数列は以下の2の冪乗を含む。（）

これらの2のべき乗の指数部分は2, 3, 5, …というような素数である。 

 FRACTRANプログラムを理解する 
FRACTRANプログラムはレジスタが引数nの素数指数として格納されるレジスタマシンとして見ることができる。

ゲーデル数を用いて、正の整数nは任意の数の任意の大きさの正の整数の変数を符号化することができるGödel numbering ゲーデル数は、慣例が適用して、直接負の整数、浮動小数点数や文字列を間接的に表すようにすることはできるが、直接的に使用することはできない。FRACTRANに提案されている拡張機能にはFRACTRAN++（Written in English）及びBag（Written in English）などがある。。 各変数の値は、整数の素因数分解によって素数のべき乗に符号化される。例えば、整数は、レジスタの状態が以下のようになっていることを表す。
 ある変数（これをv2とする）の値が2である。
 ほかの変数の2つ（これをv3とv5とする）の値が1である。
 ほかの全ての変数の値が0である。

FRACTRANプログラムは、正の分数の列である。すべての分数はそれぞれ、1つ以上の変数をテストする命令を表し、それはその分母の素因数によって表される。例えば、はv2とv5を評価する。 かつ のとき、v2から2を、v5から1をそれぞれ引き、v3に1を、v7に1を加える。以下に例を挙げる。FRACTRANプログラムは分数のリストに過ぎず、これらの評価・演算命令（加算・減算命令）はFRACTRAN言語において唯一許された命令である。さらに、以下の制約が適用される。
 命令が実行されるごとに、評価される変数はデクリメント（減算）される。
 同じ変数に対して、1つの命令でインクリメント（加算）とデクリメント（減算）を両方することはできない。（そうでなければ、その命令を表す分数が既約分数にならない。）したがって、すべてのFRACTRANの命令は変数の評価においてその変数を消費する。
 FRACTRANの命令は、変数が0かどうかを直接評価することはできない。（しかし、既定の命令を作成して、それを特定の変数を評価する別の命令の後に配置することで、間接的な評価は可能である。）

 簡単なプログラムの作成 

 加算 
最も単純なFRACTRANプログラムは以下の1つの命令である。このプログラムは以下の単純なアルゴリズムに表される。
FRACTRAN命令条件アクションv2 > 0v2から1を引き、v3に1を加えるv2 = 0停止する
の形で与えられた初期値に対し、このプログラムは以下の数列を計算する。

, , …

これをステップ行い、最終的に2で割り切れなくなり、をかけても整数とならなくなったとき、レジスタマシンはを出力して停止する。これにより、2つの整数が加算される。

 乗算 
「乗算器」は、「加算器」を「ループする」ことで作ることができる。これには、アルゴリズムにState（オブジェクト指向プログラミングにおけるデザインパターンの1つ）を導入する必要がある。このアルゴリズムはを引数に取り、を生成する。
State条件アクション次のStateAv7 > 0v7から1を引き、v3に1を加えるAv7 = 0 かつv2 > 0v2から1を引くBv7 = 0 かつv2 = 0 かつv3 > 0v3から1を引くAv7 = 0 かつv2 = 0 かつv3 = 0停止するBv3 > 0v3から1を引き、v5とv7にそれぞれ1を加えるBv3 = 0なしA
BのStateはv3とv5を加算しv3をv7に値を移すループである。また、AのStateは、BのStateをv2回繰り返す外側の制御ループである。AのStateはまた、BのStateのループが完了した後、v7からv3に値を移す（つまり、v3から一度v7に移動して、またv3に戻る）。 

新しい変数をStateインジケータとして用いることで、Stateを実行することができる。B用のStateインジケータはv11とv13である。ここで、1つのループにState制御インジケータは第一のフラグ（v11）と第二のフラグ（v13）の2つが必要となることに留意されたい。なぜなら、それぞれのインジケータは評価されると消費されるため、「現在のStateを継続せよ」と言うために第二のインジケータが必要となるからである。この第二のインジケータは、次の命令で第一のインジケータに還元され、ループが継続する。

乗算アルゴリズムの表にFRACTRAN Stateインジケータと命令を追加すると以下のようになる。
FRACTRAN命令StateStateインジケータ条件アクション次のStateAなしv7 > 0v7から1を引き、v3に1を加えるAv7 = 0
かつ v2 > 0v2から1を引くBv7 = 0 
かつv2 = 0 かつv3 > 0v3から1を引くAv7 = 0 かつv2 = 0 かつv3 = 0停止するBv11, v13v3 > 0v3から1を引き、v5とv7にそれぞれ1を加えるBv3 = 0なしA
FRACTRAN命令を書き出すとき、最後にAのStateの命令が必要になる。AのStateにはインジケータがないからである。Stateインジケータが設定されていないのが既定のStateである。ゆえに、乗算器のFRACTRANプログラムは以下のようになる。入力2a3bに対してこのプログラムは5abを出力するEsolang FRACTRAN page（Written in English）に類似した乗算器のアルゴリズムの説明がある。。 中央|サムネイル|544x544ピクセル|上記のFRACTRANプログラムで3×2を計算する（3×2は6であるから、入力はで、出力はとなる）

 減算と除算 
同様に、FRACTRAN「減算器」を作ることができる。さらに、減算を繰り返すことで、以下の「商とあまり」のアルゴリズムを作ることもできる。
FRACTRAN命令StateStateインジケータ条件アクション次のStateAv11, v13v2 > 0 かつv3 > 0v2とv3からそれぞれ1を引き、v7に1を加えるAv2 = 0 かつv3 > 0v3から1を引くXv3 = 0v5に1を加えるBBv17, v19v7 > 0v7から1を引き、v3に1を加えるBv7 = 0なしAXv3 > 0v3から1を引くXv3 = 0停止する
FRACTRANプログラムに書き出すと、以下のようになる。入力2n3d11に対して、このプログラムは5q7rを出力する。ここに、n = qd + r かつ 0 ≤ r  < dである。

 コンウェイの素数アルゴリズム 
コンウェイの素数生成アルゴリズム（前述）は本質的に、２つのループ内の商とあまりのアルゴリズムである。（ただし0 ≤ m  < n）の形で与えられた入力に対し、アルゴリズムはn+1の最大の約数kを見つけるまでn+1をnから1までの整数でそれぞれ割ろうとする。そして2n+1 7k-1を返し、繰り返す。このアルゴリズムで生成されるStateの番号の列はkが1のとき2のべき乗を生成する（7の指数は0になる）のは、2の指数が素数のときのみである。Havil (2007)に、コンウェイのアルゴリズムの段階的な説明がある。

このプログラムにおいて、素数2, 3, 5, 7 ... を得るには、それぞれ19, 69, 281, 710, ...のステップが必要となる。（）

コンウェイのプログラムには前述のものより分数が2つ異なる版も存在する; 。こちらの方が少し速い。2, 3, 5, 7... を得るのには19, 69, 280, 707... のステップが必要である。（）このプログラムの特定の整数Nが素数であるか調べる反復には、以下の数のステップが必要である。このとき、は最大のNの整数の約数であり、は床関数である。

以下は、1999年の、Devin Kilminsterによる、これより少し短い、10の命令からなるプログラムである。初期値n = 10において、連続した素数が後続する10のべき乗によって生成される。 
 他の例 
以下のFRACTRANプログラムつまり
は、2進記数法におけるaのハミング重み H(a)、すなわちaの2進数表記における1の個数を計算する。入力は2aで出力13H(a)である。John Baez, Puzzle #4, The n-Category Caféこのプログラムを解析すると以下のようになる。
FRACTRAN命令StateStateインジケータ条件アクション次のStateAv5, v11v2 > 1v2から2を引き、v3に1を加えるAv2 = 1v2から1を引き、v13に1を加えるBv2 = 0なしBBNonev3 > 0v3から1を引き、v2に1を加えるBv3 = 0 かつv7 > 0v7から1を引き、v2に1を加えるAv3 = 0 かつv7 = 0 かつv2 > 0v2から1を引き、v7に1を加えるBv2 = 0 かつv3 = 0 かつv7 = 0停止する

 注釈 

 関連項目 

 OISC
 コラッツの問題

 参考資料 




 外部リンク 

 Lecture from John Conway: "Fractran: A Ridiculous Logical Language"
 "Prime Number Pathology: Fractran"

 Prime Number Pathology
 FRACTRAN - (Esolang wiki)
 Ruby implementation and example programs
 Project Euler Problem 308
 "Building Fizzbuzz in Fractran from the Bottom Up"
 Chris Lomont, "A Universal FRACTRAN Interpreter in FRACTRAN"

Category:レクリエーション数学
Category:難解プログラミング言語
Category:計算モデル