FRACTRAN

提供: testwiki
ナビゲーションに移動 検索に移動

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

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

テンプレート:Harvnbには、PRIMEGAME(素数ゲーム)と呼ばれる、連続する素数を探索する以下のFRACTRANプログラムがある。(1791,7885,1951,2338,2933,7729,9523,7719,117,1113,1311,152,17,551)n=2として始め、このFRACTRANプログラムは以下の整数列を生成する。

2の後、この数列は以下の2の冪乗を含む。22=4,23=8,25=32,27=128,211=2048,213=8192,217=131072,219=524288,テンプレート:OEIS

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

FRACTRANプログラムを理解する

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

ゲーデル数を用いて、正の整数nは任意の数の任意の大きさの正の整数の変数符号化することができる[注釈 1]。 各変数の値は、整数の素因数分解によって素数のべき乗に符号化される。例えば、整数60=22×31×51は、レジスタの状態が以下のようになっていることを表す。

  • ある変数(これをv2とする)の値が2である。
  • ほかの変数の2つ(これをv3とv5とする)の値が1である。
  • ほかの全ての変数の値が0である。

FRACTRANプログラムは、正の分数の列である。すべての分数はそれぞれ、1つ以上の変数をテストする命令を表し、それはその分母素因数によって表される。例えば、f1=2120=3×722×51はv2とv5を評価する。v22 かつ v51のとき、v2から2を、v5から1をそれぞれ引き、v3に1を、v7に1を加える。以下に例を挙げる。60f1=22×31×513×722×51=32×71FRACTRANプログラムは分数のリストに過ぎず、これらの評価・演算命令(加算・減算命令)はFRACTRAN言語において唯一許された命令である。さらに、以下の制約が適用される。

  • 命令が実行されるごとに、評価される変数はデクリメント(減算)される。
  • 同じ変数に対して、1つの命令でインクリメント(加算)デクリメント(減算)を両方することはできない。(そうでなければ、その命令を表す分数が既約分数にならない。)したがって、すべてのFRACTRANの命令は変数の評価においてその変数を消費する。
  • FRACTRANの命令は、変数が0かどうかを直接評価することはできない。(しかし、既定の命令を作成して、それを特定の変数を評価する別の命令の後に配置することで、間接的な評価は可能である。)

簡単なプログラムの作成

最も単純なFRACTRANプログラムは以下の1つの命令である。(32)このプログラムは以下の単純なアルゴリズムに表される。

FRACTRAN
命令
条件 アクション
32 v2 > 0 v2から1を引き、v3に1を加える
v2 = 0 停止する

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

2a13b+1, 2a23b+2, …

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

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

State 条件 アクション 次のState
A v7 > 0 v7から1を引き、v3に1を加える A
v7 = 0 かつ
v2 > 0
v2から1を引く B
v7 = 0 かつ
v2 = 0 かつ
v3 > 0
v3から1を引く A
v7 = 0 かつ
v2 = 0 かつ
v3 = 0
停止する
B v3 > 0 v3から1を引き、v5とv7にそれぞれ1を加える B
v3 = 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
命令
State State
インジケータ
条件 アクション 次のState
37 A なし v7 > 0 v7から1を引き、v3に1を加える A
112 v7 = 0

かつ v2 > 0

v2から1を引く B
13 v7 = 0

かつv2 = 0 かつv3 > 0

v3から1を引く A
v7 = 0
かつv2 = 0 かつ
v3 = 0
停止する
5713311,1113 B v11, v13 v3 > 0 v3から1を引き、v5とv7にそれぞれ1を加える B
111 v3 = 0 なし A

FRACTRAN命令を書き出すとき、最後にAのStateの命令が必要になる。AのStateにはインジケータがないからである。Stateインジケータが設定されていないのが既定のStateである。ゆえに、乗算器のFRACTRANプログラムは以下のようになる。

(45533,1113,111,37,112,13)

入力2a3bに対してこのプログラムは5abを出力する[注釈 2]

上記のFRACTRANプログラムで3×2を計算する(3×2は6であるから、入力は23×32=72で、出力は56=15625となる)

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

FRACTRAN
命令
State State
インジケータ
条件 アクション 次のState
7132311,1113 A v11, v13 v2 > 0 かつ
v3 > 0
v2とv3からそれぞれ1を引き、v7に1を加える A
1311 v2 = 0 かつ
v3 > 0
v3から1を引く X
51711 v3 = 0 v5に1を加える B
319717,1719 B v17, v19 v7 > 0 v7から1を引き、v3に1を加える B
1117 v7 = 0 なし A
13 X v3 > 0 v3から1を引く X
v3 = 0 停止する

FRACTRANプログラムに書き出すと、以下のようになる。(9166,1113,133,8511,57119,1719,1117,13)入力2n3d11に対して、このプログラムは5q7rを出力する。ここに、n = qd + r かつ 0 ≤ r < dである。

コンウェイの素数アルゴリズム

コンウェイの素数生成アルゴリズム(前述)は本質的に、2つのループ内の商とあまりのアルゴリズムである。2n7m(ただし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, ...のステップが必要となる。(テンプレート:OEIS

コンウェイのプログラムには前述のものより分数が2つ異なる版も存在する[1](1791,7885,1951,2338,2933,7729,9523,7719,117,1113,1311,1514,152,551)こちらの方が少し速い。2, 3, 5, 7... を得るのには19, 69, 280, 707... のステップが必要である。(テンプレート:OEIS)このプログラムの特定の整数Nが素数であるか調べる反復には、以下の数のステップが必要である。N1+(6N+2)(Nb)+2d=bN1Ndこのとき、b<Nは最大のNの整数の約数であり、x床関数である[2]


以下は、1999年の、Devin Kilminsterによる、これより少し短い、10の命令からなるプログラムである[3](73,9998,1349,3935,3691,10143,4913,711,12,911)初期値n = 10において、連続した素数が後続する10のべき乗によって生成される。

他の例

以下のFRACTRANプログラム(311225,511,1325,15,23,257,72)つまり(2033,511,1310,15,23,107,72) は、2進記数法におけるaハミング重み H(a)、すなわちa2進数表記における1の個数を計算する。入力は2aで出力13H(a)である。[4]このプログラムを解析すると以下のようになる。

FRACTRAN
命令
State State
インジケータ
条件 アクション 次のState
311225,511 A v5, v11 v2 > 1 v2から2を引き、v3に1を加える A
1325 v2 = 1 v2から1を引き、v13に1を加える B
15 v2 = 0 なし B
23 B None v3 > 0 v3から1を引き、v2に1を加える B
257 v3 = 0 かつ
v7 > 0
v7から1を引き、v2に1を加える A
72 v3 = 0 かつ
v7 = 0 かつ
v2 > 0
v2から1を引き、v7に1を加える B
v2 = 0 かつ
v3 = 0 かつ
v7 = 0
停止する

注釈

テンプレート:Reflist

関連項目

参考資料

テンプレート:Reflist テンプレート:Refbegin

テンプレート:Refend

外部リンク


引用エラー: 「注釈」という名前のグループの <ref> タグがありますが、対応する <references group="注釈"/> タグが見つかりません