FRACTRAN

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

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

には、PRIMEGAME（素数ゲーム）と呼ばれる、連続する素数を探索する以下のFRACTRANプログラムがある。\left( \frac{17}{91}, \frac{78}{85}, \frac{19}{51}, \frac{23}{38}, \frac{29}{33}, \frac{77}{29}, \frac{95}{23}, \frac{77}{19}, \frac{1}{17}, \frac{11}{13}, \frac{13}{11}, \frac{15}{2}, \frac{1}{7}, \frac{55}{1} \right)*n*=2として始め、このFRACTRANプログラムは以下の整数列を生成する。
* 2, 15, 825, 725, 1925, 2275, 425, 390, 330, 290, 770, ... （）

2の後、この数列は以下の2の冪乗を含む。2^2=4,\, 2^3=8,\, 2^5=32,\, 2^7=128,\, 2^{11}=2048,\, 2^{13}=8192,\, 2^{17}=131072,\, 2^{19}=524288,\,  \dots（）

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

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

ゲーデル数を用いて、正の整数*n*は任意の数の任意の大きさの正の整数の変数を符号化することができる。 各変数の値は、整数の素因数分解によって素数のべき乗に符号化される。例えば、整数60 = 2^2 \times 3^1 \times 5^1は、レジスタの状態が以下のようになっていることを表す。
* ある変数（これをv2とする）の値が2である。
* ほかの変数の2つ（これをv3とv5とする）の値が1である。
* ほかの全ての変数の値が0である。

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

## 簡単なプログラムの作成

### [[加算]]
最も単純なFRACTRANプログラムは以下の1つの命令である。\left( \frac{3}{2} \right)このプログラムは以下の単純なアルゴリズムに表される。

2^a 3^bの形で与えられた初期値に対し、このプログラムは以下の数列を計算する。

2^{a-1} 3^{b+1}, 2^{a-2} 3^{b+2}, …

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

### [[乗算]]
「乗算器」は、「加算器」を「ループする」ことで作ることができる。これには、アルゴリズムにState（オブジェクト指向プログラミングにおけるデザインパターンの1つ）を導入する必要がある。このアルゴリズムは2^a 3^bを引数に取り、5^{ab}を生成する。

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命令を書き出すとき、最後にAのStateの命令が必要になる。AのStateにはインジケータがないからである。Stateインジケータが設定されていないのが既定のStateである。ゆえに、乗算器のFRACTRANプログラムは以下のようになる。\left( \frac{455}{33}, \frac{11}{13}, \frac{1}{11}, \frac{3}{7}, \frac{11}{2}, \frac{1}{3} \right)入力2*a*3*b*に対してこのプログラムは5*ab*を出力する。 

### 減算と除算
同様に、FRACTRAN「減算器」を作ることができる。さらに、減算を繰り返すことで、以下の「商とあまり」のアルゴリズムを作ることもできる。

FRACTRANプログラムに書き出すと、以下のようになる。\left( \frac{91}{66}, \frac{11}{13}, \frac{1}{33}, \frac{85}{11}, \frac{57}{119}, \frac{17}{19}, \frac{11}{17}, \frac{1}{3} \right)入力2*n*3*d*11に対して、このプログラムは5*q*7*r*を出力する。ここに、*n* = *qd* + *r* かつ 0 ≤ *r*  2^n 7^m（ただし0 ≤ *m*  *n*+1 7*k*-1を返し、繰り返す。このアルゴリズムで生成されるStateの番号の列はkが1のとき2のべき乗を生成する（7の指数は0になる）のは、2の指数が素数のときのみである。Havil (2007)に、コンウェイのアルゴリズムの段階的な説明がある。

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

コンウェイのプログラムには前述のものより分数が2つ異なる版も存在する。\left( \frac{17}{91}, \frac{78}{85}, \frac{19}{51}, \frac{23}{38}, \frac{29}{33}, \frac{77}{29}, \frac{95}{23}, \frac{77}{19}, \frac{1}{17}, \frac{11}{13}, \frac{13}{11}, \frac{15}{14}, \frac{15}{2}, \frac{55}{1} \right)こちらの方が少し速い。2, 3, 5, 7... を得るのには19, 69, 280, 707... のステップが必要である。（）このプログラムの特定の整数*N*が素数であるか調べる反復には、以下の数のステップが必要である。N - 1 + (6N+2)(N-b) + 2 \sum\limits^{N-1}_{d=b} \left\lfloor \frac{N}{d} \right\rfloorこのとき、b は最大の*N*の整数の約数であり、\lfloor x \rfloorは床関数である。

以下は、1999年の、Devin Kilminsterによる、これより少し短い、10の命令からなるプログラムである。\left( \frac{7}{3}, \frac{99}{98}, \frac{13}{49}, \frac{39}{35}, \frac{36}{91}, \frac{10}{143}, \frac{49}{13}, \frac{7}{11}, \frac{1}{2}, \frac{91}{1} \right)初期値*n* = 10において、連続した素数が後続する10のべき乗によって生成される。 
## 他の例
以下のFRACTRANプログラム\left( \frac{3 \cdot 11}{2^2 \cdot 5} , \frac{5}{11}, \frac{13}{2 \cdot 5}, \frac{1}{5}, \frac{2}{3}, \frac{2 \cdot 5}{7}, \frac{7}{2} \right)つまり\left(\frac{20}{33},\frac 5{11},\frac{13}{10},\frac 15,\frac 23,\frac{10}7,\frac 72\right)
は、2進記数法における*a*のハミング重み H(*a*)、すなわち*a*の2進数表記における1の個数を計算する。入力は2*a*で出力13H(*a*)である。このプログラムを解析すると以下のようになる。

## 注釈

## 関連項目

* 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"