FRACTRAN is a Turing-complete esoteric programming language invented by the mathematician John Horton Conway.

A FRACTRAN program is an ordered list of positive fractions 



P
=
(

f

1


,

f

2


,
…
,

f

m


)


{\displaystyle P=(f_{1},f_{2},\ldots ,f_{m})}

, together with an initial positive integer input 



n


{\displaystyle n}

.



The program is run by updating the integer 



n


{\displaystyle n}

 as follows:

 for the first fraction, 




f

i




{\displaystyle f_{i}}

, in the list for which 



n

f

i




{\displaystyle nf_{i}}

 is an integer, replace 



n


{\displaystyle n}

 with 



n

f

i




{\displaystyle nf_{i}}

 ;
 repeat this rule until no fraction in the list produces an integer when multiplied by 



n


{\displaystyle n}

, then halt.


Conway gave a program for primes in FRACTRAN:

 



17

/

91


{\displaystyle 17/91}

, 



78

/

85


{\displaystyle 78/85}

, 



19

/

51


{\displaystyle 19/51}

, 



23

/

38


{\displaystyle 23/38}

, 



29

/

33


{\displaystyle 29/33}

, 



77

/

29


{\displaystyle 77/29}

, 



95

/

23


{\displaystyle 95/23}

, 



77

/

19


{\displaystyle 77/19}

, 



1

/

17


{\displaystyle 1/17}

, 



11

/

13


{\displaystyle 11/13}

, 



13

/

11


{\displaystyle 13/11}

, 



15

/

14


{\displaystyle 15/14}

, 



15

/

2


{\displaystyle 15/2}

, 



55

/

1


{\displaystyle 55/1}


Starting with 



n
=
2


{\displaystyle n=2}

, this FRACTRAN program will change 



n


{\displaystyle n}

 to 



15
=
2
×
(
15

/

2
)


{\displaystyle 15=2\times (15/2)}

, then 



825
=
15
×
(
55

/

1
)


{\displaystyle 825=15\times (55/1)}

, generating the following sequence of integers:

 



2


{\displaystyle 2}

, 



15


{\displaystyle 15}

, 



825


{\displaystyle 825}

, 



725


{\displaystyle 725}

, 



1925


{\displaystyle 1925}

, 



2275


{\displaystyle 2275}

, 



425


{\displaystyle 425}

, 



390


{\displaystyle 390}

, 



330


{\displaystyle 330}

, 



290


{\displaystyle 290}

, 



770


{\displaystyle 770}

, 



…


{\displaystyle \ldots }


After 2, this sequence contains the following powers of 2:






2

2


=
4


{\displaystyle 2^{2}=4}

, 




2

3


=
8


{\displaystyle 2^{3}=8}

, 




2

5


=
32


{\displaystyle 2^{5}=32}

, 




2

7


=
128


{\displaystyle 2^{7}=128}

, 




2

11


=
2048


{\displaystyle 2^{11}=2048}

, 




2

13


=
8192


{\displaystyle 2^{13}=8192}

, 




2

17


=
131072


{\displaystyle 2^{17}=131072}

, 




2

19


=
524288


{\displaystyle 2^{19}=524288}

, 



…


{\displaystyle \ldots }


which are the prime powers of 2.



Task

Write a program that reads a list of fractions in a natural format from the keyboard or from a string,
to parse it into a sequence of fractions (i.e. two integers),
and runs the FRACTRAN starting from a provided integer, writing the result at each step.
It is also required that the number of steps is limited (by a parameter easy to find).



Extra credit

Use this program to derive the first 20 or so prime numbers.



See also

For more on how to program FRACTRAN as a universal programming language, see:

 J. H. Conway (1987). Fractran: A Simple Universal Programming Language for Arithmetic. In: Open Problems in Communication and Computation, pages 4–26. Springer.
 J. H. Conway (2010). "FRACTRAN: A simple universal programming language for arithmetic". In Jeffrey C. Lagarias. The Ultimate Challenge: the 3x+1 problem. American Mathematical Society. pp. 249–264. ISBN 978-0-8218-4940-8. Zbl 1216.68068.
 Number Pathology: Fractran by Mark C. Chu-Carroll; October 27, 2006.


# as the numbers required for finding the first 20 primes are quite large, #
# we use Algol 68G's LONG LONG INT with a precision of 100 digits          #
PR precision 100 PR
 
# mode to hold fractions #
MODE FRACTION = STRUCT( INT numerator, INT denominator );
 
# define / between two INTs to yield a FRACTION #
OP / = ( INT a, b )FRACTION: ( a, b );
 
# mode to define a FRACTRAN progam #
MODE FRACTRAN = STRUCT( FLEX[0]FRACTION data
                      , LONG LONG INT   n
                      , BOOL            halted
                      );
# prepares a FRACTRAN program for use - sets the initial value of n and halted to FALSE #
PRIO STARTAT = 1;
OP   STARTAT = ( REF FRACTRAN f, INT start )REF FRACTRAN:
BEGIN
    halted OF f := FALSE;
         n OF f := start;
    f
END;
 
# sets n OF f to the next number in the sequence or sets halted OF f to TRUE if the sequence has ended #
OP NEXT = ( REF FRACTRAN f )LONG LONG INT:
    IF halted OF f
    THEN n OF f := 0
    ELSE
        BOOL          found  := FALSE;
        LONG LONG INT result := 0;
        FOR pos FROM LWB data OF f TO UPB data OF f WHILE NOT found DO
            LONG LONG INT value       = n OF f * numerator OF ( ( data OF f )[ pos ] );
            INT           denominator = denominator OF ( ( data OF f )[ pos ] );
            IF found := ( value MOD denominator = 0 ) THEN result := value OVER denominator FI
        OD;
        IF NOT found THEN halted OF f := TRUE FI;
        n OF f := result
    FI ;
 
# generate and print the sequence of numbers from a FRACTRAN pogram #
PROC print fractran sequence = ( REF FRACTRAN f, INT start, INT limit )VOID:
BEGIN
    VOID( f STARTAT start );
    print( ( "0: ", whole( start, 0 ) ) );
    FOR i TO limit
    WHILE VOID( NEXT f );
          NOT halted OF f
    DO
        print( ( " " + whole( i, 0 ) + ": " + whole( n OF f, 0 ) ) )
    OD;
    print( ( newline ) )
END ;
 
# print the first 16 elements from the primes FRACTRAN program #
FRACTRAN pf := ( ( 17/91, 78/85, 19/51, 23/38, 29/33, 77/29, 95/23, 77/19, 1/17, 11/13, 13/11, 15/14,  15/2, 55/1 ), 0, FALSE );
print fractran sequence( pf, 2, 15 );
 
# find some primes using the pf FRACTRAN progam - n is prime for the members in the sequence that are 2^n #
INT primes found := 0;
VOID( pf STARTAT 2 );
INT pos := 0;
print( ( "seq position  prime sequence value", newline ) );
WHILE primes found < 20 AND NOT halted OF pf DO
    LONG LONG INT value      := NEXT pf;
    INT      power of 2 := 0;
    pos +:= 1;
    WHILE value MOD 2 = 0 AND value > 0 DO power of 2 PLUSAB 1; value OVERAB 2 OD;
    IF value = 1 THEN
        # found a prime #
        primes found +:= 1;
        print( ( whole( pos, -12 ) + " " + whole( power of 2, -6 ) + " (" + whole( n OF pf, 0 ) + ")", newline ) )
    FI
OD