FRACTRAN

Z testwiki
Przejdź do nawigacji Przejdź do wyszukiwania

FRACTRANezoteryczny język programowania wynaleziony przez matematyka Johna Conwaya[1][2], będący zupełny w sensie Turinga[3].

Program w języku FRACTRAN ma postać ciągu dodatnich ułamków nieskracalnych. Wejściem dla programu jest dodatnia liczba całkowita n. Wykonanie programu polega na wielokrotnym zmienianiu wartości n przez następującą operację: „znajdź pierwszy w ciągu ułamek f, dla którego iloczyn nf jest liczbą całkowitą, i zastąp n przez nf”. Jeśli żaden ułamek w ciągu nie daje liczby całkowitej po pomnożeniu przez obecną wartość n, wykonywanie programu zostaje zatrzymane[1].

Nazwa stanowi połączenie słowa „fraction” (ułamek) oraz nazwy języka programowania FORTRAN[3].

Przykładowym programem w języku FRACTRAN jest PRIMEGAME[uwaga 1] autorstwa Conwaya[1], który po uruchomieniu znajduje kolejne liczby pierwsze:

(1791,7885,1951,2338,2933,7729,9523,7719,117,1113,1311,152,17,551).

Jeśli na wejściu zostanie podana liczba n=2, program ten generuje następujący ciąg liczb:

  • 2, 15, 825, 725, 1925, 2275, 425, 390, 330, 290, 770, 910, 170, 156, 132, 116, 308, 364, 68, 4, ... Szablon:OEIS

Nie licząc początkowej dwójki, ciąg ten zawiera następujące potęgi 2: 4=22,8=23,32=25,128=27,2048=211,8192=213,131072=217,524288=219,Szablon:OEIS. Wykładniki tych potęg są kolejnymi liczbami pierwszymi.

Zasada działania programu FRACTRAN

Program FRACTRAN można rozumieć jako rodzaj maszyny rejestrowej, gdzie zawartość rejestrów jest przechowywana w wykładnikach potęg czynników pierwszych w rozkładzie argumentu n[2]. Na przykład wartość n równa 60=22×31×51 reprezentuje stan rejestrów, w którym jedna zmienna (nazwana v2) ma wartość 2, a dwie inne zmienne (v3 i v5) mają wartość 1. Wszystkie inne zmienne mają wartość 0.

Program FRACTRAN ma postać uporządkowanej listy dodatnich ułamków nieskracalnych. Każdy ułamek reprezentuje instrukcję, która przeprowadza operacje na zawartości jednej lub więcej zmiennych, określonych przez czynniki pierwsze mianownika danego ułamka. Na przykład instrukcja

f1=2120=31×7122×51

sprawdza zawartość v2 i v5. Jeśli v22 i v51, instrukcja f1 odejmie 2 od v2 i 1 od v5 oraz doda 1 do v3 i 1 do v7. Na przykład:

60f1=22×31×5131×7122×51=32×71.

Tego rodzaju instrukcje „sprawdź-odejmij-dodaj” są w języku FRACTRAN jedynymi dozwolonymi instrukcjami[2].

Przykładowe programy FRACTRAN

Dodawanie

Najprostszy program FRACTRAN składa się z pojedynczej instrukcji, na przykład[1]

(32).

Program ten oblicza sumę dwóch liczb całkowitych, a i b. Dla początkowej wartości n=2a3b program generuje sekwencję 2a13b+1, 2a23b+2 itd., aż w końcu, po a krokach, program zatrzyma się z końcowym wynikiem 3a+b.

Nieco bardziej skomplikowany wariant programu dodającego składa się z dwóch instrukcji[2]:

(103,35).

Dla wejściowej wartości n=2a3b program zatrzyma się z wynikiem 2a+b3b. Dzięki temu informacja o wartościach a i b nie zostaje zniszczona.

W tym wariancie zmienna v5 tymczasowo przechowuje początkową wartość v3 = b. Pierwsza instrukcja 103=253 przenosi zawartość v3 do v2 oraz v5; gdy v3 osiągnie wartość zero, program zaczyna wykonywać drugą instrukcję 35, która odtwarza wartość v3 z v5.

Mnożenie – przykład pętli

Następujący program[2] przyjmuje na wejściu liczbę n=2a3b7c11 i zatrzymuje się z końcowym wynikiem n=2a+bc3b11, tym samym obliczając wynik mnożenia bc:

(1377,17039,1317,1913,6995,1923,1119).

Działanie programu polega na wykonywaniu procedury dodającej w pętli, tak, by dodać b do a dokładnie c razy.

Aby zaimplementować w języku FRACTRAN pętlę, należy wprowadzić pojęcie stanu. W tym celu należy wybrać pewne liczby pierwsze jako wskaźniki stanu: dla powyższego programu mnożącego są to 11, 13, 17, 19 i 23. Na przykład jeśli w danym kroku wartość n jest podzielna przez 11 i niepodzielna przez żadną inną z tych liczb, oznacza to, że program jest w stanie „11”.

By przeanalizować działanie programu, dla większej jasności można go zapisać w następujący sposób:

(13711,2517313,1317,1913,323519,1923,1119).

Działanie programu można opisać następująco[2]:

  • w chwili początkowej (wejściowa wartość n=2a3b7c11) program jest w stanie 11. W pierwszym kroku – jeśli v7 > 0 – odejmuje 1 od v7 i przechodzi do stanu 13;
  • w kolejnych krokach program przechodzi na przemian między stanami 13 a 17 (pierwsza pętla). W każdym przebiegu tej pętli wykonuje pierwszą instrukcję algorytmu dodającego („odejmij 1 od v3 i dodaj 1 do v2, v5”);
  • gdy v3 osiągnie zero, pętla kończy się – ze stanu 13 program przechodzi do 19;
  • w kolejnych krokach program przechodzi na przemian między stanami 19 a 23 (druga pętla). W każdym przebiegu tej pętli wykonuje drugą instrukcję algorytmu dodającego („odejmij 1 od v5, dodaj 1 do v3”);
  • gdy v5 osiąga zero, druga pętla kończy się, a program przechodzi do początkowego stanu 11 i wykonywanie instrukcji zaczyna się od nowa.

Po każdym wykonaniu tego ciągu instrukcji zawartość v2 wzrasta o b, a zawartość v7 maleje o 1. Gdy v7 osiąga zero, program zatrzymuje się.

Algorytm generowania liczb pierwszych (PRIMEGAME)

Zaprezentowany na wstępie program PRIMEGAME, po wprowadzeniu na wejściu liczby n=21, przeprowadza kolejno test pierwszości dla liczb N=2,3,4,5... w następujący sposób. Program wykonuje pętlę, próbując podzielić liczbę N przez wszystkie możliwe dzielniki d=N1,N2,1. (Dzielenie zaimplementowane jest jako wielokrotne odejmowanie d od N, aż do uzyskania całkowitej części ilorazu oraz reszty z dzielenia.) Gdy program natrafi na największą wartość d, która dzieli N bez reszty, wyprowadza wartość n=2N7d1 i wykonuje algorytm od nowa dla kolejnej wartości N. Wartość 2N7d1 jest potęgą dwójki tylko wtedy, gdy d wynosi 1 – co ma miejsce tylko wtedy, gdy N jest liczbą pierwszą. Dokładniejsze wyjaśnienie krok po kroku algorytmu Conwaya można znaleźć u Guya (1983)[4] bądź Havila (2007)[2].

Dotarcie do liczby pierwszej 2, 3, 5, 7... zajmuje temu programowi odpowiednio 19, 69, 281, 710,... kroków od momentu uruchomienia Szablon:OEIS.

Istnieje także wariant programu Conwaya[4][5], który różni się od powyższej wersji dwoma ułamkami:

(1791,7885,1951,2338,2933,7729,9523,7719,117,1113,1311,1514,152,551)

Zasada działania tego wariantu jest taka sama, ale jest on nieco szybszy: by dotrzeć do kolejnych liczb pierwszych 2, 3, 5, 7..., potrzebuje on odpowiednio 19, 69, 280, 707... kroków Szablon:OEIS. Pojedynczy przebieg programu, sprawdzający, czy liczba N jest pierwsza, wymaga następującej liczby kroków:

N1+(6N+2)(Nb)+2d=bN1Nd,

gdzie b<N jest największym dzielnikiem całkowitym N, a x jest częścią całkowitą x[2][4].

W roku 1999 matematyk Devin Kilminster zademonstrował krótszy program znajdujący liczby pierwsze[2], składający się z dziesięciu instrukcji:

(73,9998,1349,3935,3691,10143,4913,711,12,911)

Dla początkowego wejścia n=10 kolejne liczby pierwsze są otrzymywane jako wykładniki potęg liczby 10.

Uwagi

Szablon:Uwagi

Bibliografia

Szablon:Przypisy

Linki zewnętrzne


Błąd rozszerzenia cite: Istnieje znacznik <ref> dla grupy o nazwie „uwaga”, ale nie odnaleziono odpowiedniego znacznika <references group="uwaga"/>