2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,12 +1,14 @@
'''[[wp:FRACTRAN|FRACTRAN]]''' is a Turing-complete esoteric programming language invented by the mathematician [[wp:John Horton Conway|John Horton Conway]].
'''[[wp:FRACTRAN|FRACTRAN]]''' is a Turing-complete esoteric programming language invented by the mathematician [[wp:John Horton Conway|John Horton Conway]].
A FRACTRAN program is an ordered list of positive fractions <math>P = (f_1, f_2, \ldots, f_m)</math>, together with an initial positive integer input <math>n</math>.
The program is run by updating the integer <math>n</math> as follows:
* for the first fraction, <math>f_i</math>, in the list for which <math>nf_i</math> is an integer, replace <math>n</math> with <math>nf_i</math> ;
* repeat this rule until no fraction in the list produces an integer when multiplied by <math>n</math>, then halt.
<br>
Conway gave a program for primes in FRACTRAN:
: <math>17/91</math>, <math>78/85</math>, <math>19/51</math>, <math>23/38</math>, <math>29/33</math>, <math>77/29</math>, <math>95/23</math>, <math>77/19</math>, <math>1/17</math>, <math>11/13</math>, <math>13/11</math>, <math>15/14</math>, <math>15/2</math>, <math>55/1</math>
@ -21,17 +23,23 @@ After 2, this sequence contains the following powers of 2:
which are the prime powers of 2.
'''Your task''' is to
write a program that reads a list of fractions in a ''natural'' format from the keyboard or from a string,
;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 step is limited (by a parameter easy to find).
'''Extra credit:''' Use this program to derive the first 20 or so prime numbers.
;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 426. 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. 249264. ISBN 978-0-8218-4940-8. Zbl 1216.68068.
* [http://scienceblogs.com/goodmath/2006/10/27/prime-number-pathology-fractra/Prime Number Pathology: Fractran] by Mark C. Chu-Carroll; October 27, 2006.
<br><br>

View file

@ -0,0 +1,74 @@
# 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

View file

@ -0,0 +1,66 @@
defmodule Fractran do
use Bitwise
defp binary_to_ratio(b) do
[_, num, den] = Regex.run(~r/(\d+)\/(\d+)/, b)
{String.to_integer(num), String.to_integer(den)}
end
def load(program) do
String.split(program) |> Enum.map(&binary_to_ratio(&1))
end
defp step(_, []), do: :halt
defp step(n, [f|fs]) do
{p, q} = mulrat(f, {n, 1})
case q do
1 -> p
_ -> step(n, fs)
end
end
def exec(k, n, program) do
exec(k-1, n, fn (_) -> true end, program, [n]) |> Enum.reverse
end
def exec(k, n, pred, program) do
exec(k-1, n, pred, program, [n]) |> Enum.reverse
end
defp exec(0, _, _, _, steps), do: steps
defp exec(k, n, pred, program, steps) do
case step(n, program) do
:halt -> steps
m -> if pred.(m), do: exec(k-1, m, pred, program, [m|steps]),
else: exec(k, m, pred, program, steps)
end
end
def is_pow2(n), do: band(n, n-1) == 0
def lowbit(n), do: lowbit(n, 0)
defp lowbit(n, k) do
case band(n, 1) do
0 -> lowbit(bsr(n, 1), k + 1)
1 -> k
end
end
# rational multiplication
defp mulrat({a, b}, {c, d}) do
{p, q} = {a*c, b*d}
g = gcd(p, q)
{div(p, g), div(q, g)}
end
defp gcd(a, 0), do: a
defp gcd(a, b), do: gcd(b, rem(a, b))
end
primegen = Fractran.load("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")
IO.puts "The first few states of the Fractran prime automaton are:\n#{inspect Fractran.exec(20, 2, primegen)}\n"
prime = Fractran.exec(26, 2, &Fractran.is_pow2/1, primegen)
|> Enum.map(&Fractran.lowbit/1)
|> tl
IO.puts "The first few primes are:\n#{inspect prime}"

View file

@ -0,0 +1,59 @@
#! /usr/bin/escript
-mode(native).
-import(lists, [map/2, reverse/1]).
binary_to_ratio(B) ->
{match, [_, Num, Den]} = re:run(B, "([0-9]+)/([0-9]+)"),
{binary_to_integer(binary:part(B, Num)),
binary_to_integer(binary:part(B, Den))}.
load(Program) ->
map(fun binary_to_ratio/1, re:split(Program, "[ ]+")).
step(_, []) -> halt;
step(N, [F|Fs]) ->
{P, Q} = mulrat(F, {N, 1}),
case Q of
1 -> P;
_ -> step(N, Fs)
end.
exec(K, N, Program) -> reverse(exec(K - 1, N, fun (_) -> true end, Program, [N])).
exec(K, N, Pred, Program) -> reverse(exec(K - 1, N, Pred, Program, [N])).
exec(0, _, _, _, Steps) -> Steps;
exec(K, N, Pred, Program, Steps) ->
case step(N, Program) of
halt -> Steps;
M -> case Pred(M) of
true -> exec(K - 1, M, Pred, Program, [M|Steps]);
false -> exec(K, M, Pred, Program, Steps)
end
end.
is_pow2(N) -> N band (N - 1) =:= 0.
lowbit(N) -> lowbit(N, 0).
lowbit(N, K) ->
case N band 1 of
0 -> lowbit(N bsr 1, K + 1);
1 -> K
end.
main(_) ->
PrimeGen = load("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"),
io:format("The first few states of the Fractran prime automaton are: ~p~n~n", [exec(20, 2, PrimeGen)]),
io:format("The first few primes are: ~p~n", [tl(map(fun lowbit/1, exec(26, 2, fun is_pow2/1, PrimeGen)))]).
% rational multiplication
mulrat({A, B}, {C, D}) ->
{P, Q} = {A*C, B*D},
G = gcd(P, Q),
{P div G, Q div G}.
gcd(A, 0) -> A;
gcd(A, B) -> gcd(B, A rem B).

View file

@ -0,0 +1,2 @@
C:\Nicky\RosettaCode\FRACTRAN\FRACTRAN.for(6) : Warning: This name has not been given an explicit type. [M]
INTEGER P(M),Q(M)!The terms of the fractions.

View file

@ -0,0 +1,49 @@
INTEGER FUNCTION FRACTRAN(N,P,Q,M) !Notion devised by J. H. Conway.
Careful: the rule is N*P/Q being integer. N*6/3 is integer always because this is N*2/1, but 3 may not divide N.
Could check GCD(P,Q), dividing out the common denominator so MOD(N,Q) works.
INTEGER*8 N !The work variable. Modified!
INTEGER M !The number of fractions supplied.
INTEGER P(M),Q(M)!The terms of the fractions.
INTEGER I !A stepper.
DO I = 1,M !Search the supplied fractions, P(i)/Q(i).
IF (MOD(N,Q(I)).EQ.0) THEN !Does the denominator divide N?
N = N/Q(I)*P(I) !Yes, compute N*P/Q but trying to dodge overflow.
FRACTRAN = I !Report the hit.
RETURN !Done!
END IF !Otherwise,
END DO !Try the next fraction in the order supplied.
FRACTRAN = 0 !No hit.
END FUNCTION FRACTRAN !That's it! Even so, "Turing complete"...
PROGRAM POKE
INTEGER FRACTRAN !Not the default type of function.
INTEGER P(66),Q(66) !Holds the fractions as P(i)/Q(i).
INTEGER*8 N !The working number.
INTEGER I,IT,L,M !Assistants.
WRITE (6,1) !Announce.
1 FORMAT ("Interpreter for J.H. Conway's FRACTRAN language.")
Chew into an example programme.
OPEN (10,FILE = "Fractran.txt",STATUS="OLD",ACTION="READ") !Rather than compiled-in stuff.
READ (10,*) L !I need to know this without having to scan the input.
WRITE (6,2) L !Reveal in case of trouble.
2 FORMAT (I0," fractions, as follow:") !Should the input evoke problems.
READ (10,*) (P(I),Q(I),I = 1,L) !Ask for the specified number of P,Q pairs.
WRITE (6,3) (P(I),Q(I),I = 1,L) !Show what turned up.
3 FORMAT (24(I0,"/",I0:", ")) !As P(i)/Q(i) pairs. The colon means that there will be no trailing comma.
READ (10,*) N,M !The start value, and the step limit.
CLOSE (10) !Finished with input.
WRITE (6,4) N,M !Hopefully, all went well.
4 FORMAT ("Start with N = ",I0,", step limit ",I0)
Commence.
WRITE (6,10) 0,N !Splat a heading.
10 FORMAT (/," Step #F: N",/,I6,4X,": ",I0) !Matched FORMAT 11.
DO I = 1,M !Here we go!
IT = FRACTRAN(N,P,Q,L) !Do it!
WRITE (6,11) I,IT,N !Show it!
11 FORMAT (I6,I4,": ",I0) !N last, as it may be big.
IF (IT.LE.0) EXIT !No hit, so quit.
END DO !The next step.
END !Whee!

View file

@ -0,0 +1,11 @@
DO I = 1,M !Here we go!
IT = FRACTRAN(N,P,Q,L) !Do it!
IF (POPCNT(N).EQ.1) WRITE (6,11) I,IT,N !Show it!
11 FORMAT (I6,I4,": ",I0) !N last, as it may be big.
IF (IT.LE.0) EXIT !No hit, so quit.
IF (N.LE.0) THEN !Otherwise, worry about overflow.
WRITE (6,*) "Integer overflow!" !Justified. The test is not certain.
WRITE (6,11) I,IT,N !Alas, the step failed.
EXIT !Give in.
END IF !So much for overflow.
END DO !The next step.

View file

@ -0,0 +1,188 @@
MODULE CONWAYSIDEA !Notion devised by J. H. Conway.
USE PRIMEBAG !This is a common need.
INTEGER LASTP,ENUFF !Some size allowances.
PARAMETER (LASTP = 66, ENUFF = 66) !Should suffice for the example in mind.
INTEGER NPPOW(1:LASTP) !Represent N as a collection of powers of prime numbers.
TYPE FACTORED !But represent P and Q of freaction = P/Q
INTEGER PNUM(0:LASTP) !As a list of prime number indices with PNUM(0) the count.
INTEGER PPOW(LASTP) !And the powers. for the fingered primes.
END TYPE FACTORED !Rather than as a simple number multiplied out.
TYPE(FACTORED) FP(ENUFF),FQ(ENUFF) !Thus represent a factored fraction, P(i)/Q(i).
INTEGER PLIVE(ENUFF),NL !Helps subroutine SHOWN display NPPOW.
CONTAINS !Now for the details.
SUBROUTINE SHOWFACTORS(N) !First, to show an internal data structure.
TYPE(FACTORED) N !It is supplied as a list of prime factors.
INTEGER I !A stepper.
DO I = 1,N.PNUM(0) !Step along the list.
IF (I.GT.1) WRITE (MSG,"('x',$)") !Append a glyph for "multiply".
WRITE (MSG,"(I0,$)") PRIME(N.PNUM(I)) !The prime fingered in the list.
IF (N.PPOW(I).GT.1) WRITE (MSG,"('^',I0,$)") N.PPOW(I) !With an interesting power?
END DO !On to the next element in the list.
WRITE (MSG,1) N.PNUM(0) !End the line
1 FORMAT (": Factor count ",I0) !With a count of prime factors.
END SUBROUTINE SHOWFACTORS !Hopefully, this will not be needed often.
TYPE(FACTORED) FUNCTION FACTOR(IT) !Into a list of primes and their powers.
INTEGER IT,N !The number and a copy to damage.
INTEGER P,POW !A stepper and a power.
INTEGER F,NF !A factor and a counter.
IF (IT.LE.0) STOP "Factor only positive numbers!" !Or else...
N = IT !A copy I can damage.
NF = 0 !No factors found.
P = 0 !Because no primes have been tried.
PP:DO WHILE (IT.GT.1) !Step through the possibilities.
P = P + 1 !Another prime impends.
F = PRIME(P) !Grab a possible factor.
POW = 0 !It has no power yet.
FP:DO WHILE(MOD(N,F).EQ.0) !Well?
POW = POW + 1 !Count a factor..
N = N/F !Reduce the number.
END DO FP !The P'th prime's power's produced.
IF (POW.GT.0) THEN !So, was it a factor?
IF (NF.GE.LASTP) THEN !Yes. Have I room in the list?
WRITE (MSG,1) IT,LASTP !Alas.
1 FORMAT ("Factoring ",I0," but with provision for only ",
1 I0," prime factors!")
FACTOR.PNUM(0) = NF !Place the count so far,
CALL SHOWFACTORS(FACTOR)!So this can be invoked.
STOP "Not enough storage!" !Quite.
END IF !But normally,
NF = NF + 1 !Admit another factor.
FACTOR.PNUM(NF) = P !Identify the prime.
FACTOR.PPOW(NF) = POW !Place its power.
END IF !So much for that factor.
IF (N.LE.1) EXIT PP !Perhaps nothing remains?
END DO PP !Try another prime.
FACTOR.PNUM(0) = NF !Place the count.
END FUNCTION FACTOR !Thus, a list of primes and their powers.
INTEGER FUNCTION GCD(I,J) !Greatest common divisor.
INTEGER I,J !Of these two integers.
INTEGER N,M,R !Workers.
N = MAX(I,J) !Since I don't want to damage I or J,
M = MIN(I,J) !These copies might as well be the right way around.
1 R = MOD(N,M) !Divide N by M to get the remainder R.
IF (R.GT.0) THEN !Remainder zero?
N = M !No. Descend a level.
M = R !M-multiplicity has been removed from N.
IF (R .GT. 1) GO TO 1 !No point dividing by one.
END IF !If R = 0, M divides N.
GCD = M !There we are.
END FUNCTION GCD !Euclid lives on!
INTEGER FUNCTION FRACTRAN(L) !Applies Conway's idea to a list of fractions.
Could abandon all parameters since global variables have the details...
INTEGER L !The last fraction to consider.
INTEGER I,NF !Assistants.
DO I = 1,L !Step through the fractions in the order they were given.
NF = FQ(I).PNUM(0) !How many factors are listed in FQ(I)?
IF (ALL(NPPOW(FQ(I).PNUM(1:NF)) !Can N (as NPPOW) be divided by Q (as FQ)?
1 .GE. FQ(I).PPOW(1:NF))) THEN !By comparing the supplies of prime factors.
FRACTRAN = I !Yes!
NPPOW(FQ(I).PNUM(1:NF)) = NPPOW(FQ(I).PNUM(1:NF)) !Remove prime powers from N
1 - FQ(I).PPOW(1:NF) !Corresponding to Q.
NF = FP(I).PNUM(0) !Add powers to N
NPPOW(FP(I).PNUM(1:NF)) = NPPOW(FP(I).PNUM(1:NF)) !Corresponding to P.
1 + FP(I).PPOW(1:NF) !Thus, N = N/Q*P.
RETURN !That's all it takes! No multiplies nor divides!
END IF !So much for that fraction.
END DO !This relies on ALL(zero tests) yielding true, as when Q = 1.
FRACTRAN = 0 !No hit.
END FUNCTION FRACTRAN !No massive multi-precision arithmetic!
SUBROUTINE SHOWN(S,F) !Service routine to show the state after a step is calculated.
Could imaging a function I6FMT(23) that returns " 23" and " " for non-positive numbers.
Can't do it, as if this were invoked via a WRITE statement, re-entrant use of WRITE usually fails.
INTEGER S,F !Step number, Fraction number.
INTEGER I !A stepper.
CHARACTER*(9+4+1 + NL*6) ALINE !A scratchpad matching FORMAT 103.
WRITE (ALINE,103) S,F,NPPOW(PLIVE(1:NL)) !Show it!
103 FORMAT (I9,I4,":",<NL>I6) !As a sequence of powers of primes.
IF (F.LE.0) ALINE(10:13) = "" !Scrub when no fraction is fingered.
DO I = 1,NL !Step along the live primes.
IF (NPPOW(PLIVE(I)).GT.0) CYCLE !Ignoring the empowered ones.
ALINE(15 + (I - 1)*6:14 + I*6) = "" !Blank out zero powers.
END DO !On to the next.
WRITE (MSG,"(A)") ALINE !Reveal at last.
END SUBROUTINE SHOWN !A struggle.
END MODULE CONWAYSIDEA !Simple...
PROGRAM POKE
USE CONWAYSIDEA !But, where does he get his ideas from?
INTEGER P(ENUFF),Q(ENUFF) !Holds the fractions as P(i)/Q(i).
INTEGER N !The working number.
INTEGER LF !Last fraction given.
INTEGER LP !Last prime needed.
INTEGER MS !Maximum number of steps.
INTEGER I,IT !Assistants.
LOGICAL*1 PUSED(ENUFF) !Track the usage of prime numbers,
MSG = 6 !Standard output.
WRITE (6,1) !Announce.
1 FORMAT ("Interpreter for J. H. Conway's FRACTRAN language.")
Chew into an example programme.
10 OPEN (10,FILE = "Fractran.txt",STATUS="OLD",ACTION="READ") !Rather than compiled-in stuff.
READ (10,*) LF !I need to know this without having to scan the input.
WRITE (MSG,11) LF !Reveal in case of trouble.
11 FORMAT (I0," fractions, as follow:") !Should the input evoke problems.
READ (10,*) (P(I),Q(I),I = 1,LF) !Ask for the specified number of P,Q pairs.
WRITE (MSG,12) (P(I),Q(I),I = 1,LF) !Show what turned up.
12 FORMAT (24(I0,"/",I0:", ")) !As P(i)/Q(i) pairs. The colon means that there will be no trailing comma.
READ (10,*) N,MS !The start value, and the step limit.
CLOSE (10) !Finished with input.
WRITE (MSG,13) N,MS !Hopefully, all went well.
13 FORMAT ("Start with N = ",I0,", step limit ",I0)
IF (.NOT.GRASPPRIMEBAG(66)) STOP "Gan't grab my file of primes!" !Attempt in hope.
Convert the starting number to a more convenient form, an array of powers of successive prime numbers.
20 FP(1) = FACTOR(N) !Borrow one of the factor list variables.
NPPOW = 0 !Clear all prime factor counts.
DO I = 1,FP(1).PNUM(0) !Now find what they are.
NPPOW(FP(1).PNUM(I)) = FP(1).PPOW(I) !Convert from a variable-length list
END DO !To a fixed-length random-access array.
PUSED = NPPOW.GT.0 !Note which primes have been used.
LP = FP(1).PNUM(FP(1).PNUM(0)) !Recall the last prime required. More later.
Convert the supplied P(i)/Q(i) fractions to lists of prime number factors and powers in FP(i) and FQ(i).
DO I = 1,LF !Step through the fractions.
IT = GCD(P(I),Q(I)) !Suspicion.
IF (IT.GT.1) THEN !Justified?
WRITE (MSG,21) I,P(I),Q(I),IT !Alas. Complain. The rule is N*(P/Q) being integer.
21 FORMAT ("Fraction ",I3,", ",I0,"/",I0,!N*6/3 is integer always because this is N*2/1, but 3 may not divide N.
1 " has common factor ",I0,"!") !By removing IT,
P(I) = P(I)/IT !The test need merely check if N is divisible by Q.
Q(I) = Q(I)/IT !And, as N is factorised in NPPOW
END IF !And Q in FQ, subtractions of powers only is needed.
FP(I) = FACTOR(P(I)) !Righto, form the factor list for P.
PUSED(FP(I).PNUM(1:FP(I).PNUM(0))) = .TRUE. !Mark which primes it fingers.
LP = MAX(LP,FP(I).PNUM(FP(I).PNUM(0))) !One has no prime factors: PNUM(0) = 0.
FQ(I) = FACTOR(Q(I)) !And likewise for Q.
PUSED(FQ(I).PNUM(1:FQ(I).PNUM(0))) = .TRUE. !Some primes may be omitted.
LP = MAX(LP,FQ(I).PNUM(FQ(I).PNUM(0))) !If no prime factors, PNUM(0) fingers element zero, which is zero.
END DO !All this messing about saves on multiplication and division.
Check which primes are in use, preparing an index of live primes..
NL = 0 !No live primes.
DO I = 1,LP !Check up to the last prime.
IF (PUSED(I)) THEN !This one used?
NL = NL + 1 !Yes. Another.
PLIVE(NL) = I !Fingered.
END IF !So much for that prime.
END DO !On to the next.
WRITE (MSG,22) NL,LP,PRIME(LP) !Remark on usage.
22 FORMAT ("Require ",I0," primes only, up to Prime(",I0,") = ",I0) !Presume always more than one prime.
IF (LP.GT.LASTP) STOP "But, that's too many for array NPPOW!"
Cast forth a heading.
100 WRITE (MSG,101) (PRIME(PLIVE(I)), I = 1,NL) !Splat a heading.
101 FORMAT (/,14X,"N as powers of prime factors",/, !The prime heading,
1 5X,"Step F#:",<LP>I6) !With primes beneath.
CALL SHOWN(0,0) !Initial state of N as NPPOW. Step zero, no fraction.
Commence!
DO I = 1,MS !Here we go!
IT = FRACTRAN(LF) !Do it!
CALL SHOWN(I,IT) !Show it!
IF (IT.LE.0) EXIT !Quit it?
END DO !The next step.
Complete!
END !Whee!

View file

@ -0,0 +1,5 @@
DO I = 1,MS !Here we go!
IT = FRACTRAN(LF) !Do it!
IF (ALL(NPPOW(2:LP).EQ.0)) CALL SHOWN(I,IT) !Show it!
IF (IT.LE.0) EXIT !Quit it?
END DO !The next step.

View file

@ -6,7 +6,3 @@ fractran fracts n = n :
case find (\f -> n `mod` denominator f == 0) fracts of
Nothing -> []
Just f -> fractran fracts $ truncate (fromIntegral n * f)
main :: IO ()
main = print $ take 15 $ fractran [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] 2

View file

@ -0,0 +1 @@
import Data.List.Split (splitOn)

View file

@ -0,0 +1,3 @@
readProgram :: String -> [Ratio a]
readProgram = map (toFrac . splitOn "/") . splitOn ","
where toFrac [n,d] = read n % read d

View file

@ -0,0 +1 @@
import Data.Maybe (mapMaybe)

View file

@ -0,0 +1,6 @@
primes = mapMaybe log2 $ fractran prog 2
where
prog = [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]
log2 = fmap (+ 1) . findIndex (== 2) . takeWhile even . iterate (`div` 2)

View file

@ -0,0 +1,43 @@
open Num
let get_input () =
num_of_int (
try int_of_string Sys.argv.(1)
with _ -> 10)
let get_max_steps () =
try int_of_string Sys.argv.(2)
with _ -> 50
let read_program () =
let line = read_line () in
let words = Str.split (Str.regexp " +") line in
List.map num_of_string words
let is_int n = n =/ (integer_num n)
let run_program num prog =
let replace n =
let rec step = function
| [] -> None
| h :: t ->
let n' = h */ n in
if is_int n' then Some n' else step t in
step prog in
let rec repeat m lim =
Printf.printf " %s\n" (string_of_num m);
if lim = 0 then print_endline "Reached max step limit" else
match replace m with
| None -> print_endline "Finished"
| Some x -> repeat x (lim-1)
in
let max_steps = get_max_steps () in
repeat num max_steps
let () =
let num = get_input () in
let prog = read_program () in
run_program num prog

View file

@ -0,0 +1,15 @@
\\ FRACTRAN
\\ 4/27/16 aev
fractran(val,ft,lim)={
my(ftn=#ft,fti,di,L=List(),j=0);
while(val&&j<lim, listput(L,val);
for(i=1,ftn, fti=ft[i]; di=denominator(fti);
if(val%di==0, break));\\fend i
val= numerator(fti)*val/di; j++);\\wend j
return(Vec(L));
}
{\\ Executing:
my(v=[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]);
print(fractran(2,v,15));
}

View file

@ -1,6 +1,5 @@
sub ft (\n) {
first Int, map (* * n).narrow,
|<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
sub fractran(@program) {
2, { +first Int, map (* * $_).narrow, @program } ... 0
}
constant FT = 2, &ft ... 0;
say FT[^100];
say fractran(<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>)[^100];

View file

@ -1,7 +1,4 @@
constant FT = 2, &ft ... 0;
constant FT2 = FT.grep: { not $_ +& ($_ - 1) }
for 1..* -> $i {
given FT2[$i] {
say $i, "\t", .msb, "\t", $_;
}
for fractran <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> {
say $++, "\t", .msb, "\t", $_ if .log %% log(2);
}

View file

@ -1,23 +1,24 @@
/*REXX pgm runs FRACTRAN for a given set of fractions and from a given N*/
numeric digits 999 /*be able to handle larger nums. */
parse arg N terms fracs /*get optional arguments from CL.*/
if N=='' | N==',' then N=2 /*N specified? No, use default.*/
if terms==''|terms==',' then terms=100 /*TERMS specified? Use default.*/
if fracs='' then fracs= , /*any fractions specified? No···*/
'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'
f=space(fracs,0) /* [↑] use default for fractions.*/
do i=1 while f\==''; parse var f n.i '/' d.i ',' f
end /*i*/ /* [↑] parse all the fractions.*/
#=i-1 /*the number of fractions found. */
say # 'fractions:' fracs /*display # and actual fractions.*/
say 'N is starting at ' N /*display the starting number N.*/
say terms ' terms are being shown:' /*display a kind of header/title.*/
/*REXX program runs FRACTRAN for a given set of fractions and from a specified N. */
numeric digits 2000 /*be able to handle larger numbers. */
parse arg N terms fracs /*obtain optional arguments from the CL*/
if N=='' | N=="," then N=2 /*Not specified? Then use the default.*/
if terms=='' | terms=="," then terms=100 /* " " " " " " */
if fracs='' then fracs= '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'
/* [↑] The default for the fractions. */
f=space(fracs,0) /*remove all blanks from the FRACS list*/
do #=1 while f\==''; parse var f n.# '/' d.# "," f
end /*#*/ /* [↑] parse all the fractions in list*/
#=#-1 /*the number of fractions just found. */
say # 'fractions:' fracs /*display number and actual fractions. */
say 'N is starting at ' N /*display the starting number N. */
say terms ' terms are being shown:' /*display a kind of header/title. */
do j=1 for terms /*perform loop once for each term*/
do k=1 for #; if N//d.k\==0 then iterate /*not an integer?*/
say right('term' j,35) ' ' N /*display the Nth term with N. */
N = N % d.k * n.k /*calculate the next term (use %)*/
leave /*go start calculating next term.*/
end /*k*/ /* [↑] if integer, found a new N*/
end /*j*/
/*stick a fork in it, we're done.*/
do j=1 for terms /*perform the DO loop for each term. */
do k=1 for # /* " " " " " " fraction*/
if N//d.k\==0 then iterate /*Not an integer? Then ignore it. */
say right('term' j, 35) "──► " N /*display the Nth term with the N. */
N=N % d.k * n.k /*calculate next term (use %≡integer ÷)*/
iterate j /*go start calculating the next term. */
end /*k*/ /* [↑] if an integer, we found a new N*/
end /*j*/ /*stick a fork in it, we're all done. */

View file

@ -1,35 +1,35 @@
/*REXX pgm runs FRACTRAN for a given set of fractions and from a given N*/
numeric digits 999; w=length(digits()) /*be able to handle larger nums. */
parse arg N terms fracs /*get optional arguments from CL.*/
if N=='' | N==',' then N=2 /*N specified? No, use default.*/
if terms==''|terms==',' then terms=100 /*TERMS specified? Use default.*/
if fracs='' then fracs= , /*any fractions specified? No···*/
'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'
f=space(fracs,0) /* [↑] use default for fractions.*/
L=length(N) /*length in decimal digits of N.*/
tell= terms>0 /*flag: show # or a power of 2.*/
do i=1 while f\==''; parse var f n.i '/' d.i ',' f
end /*i*/ /* [↑] parse all the fractions.*/
!.=0 /*default value for powers of 2.*/
if \tell then do p=0 until length(_)>digits(); _=2**p; !._=1
if p<2 then @._=left('',w+9) '2**'left(p,w) " "
/*REXX program runs FRACTRAN for a given set of fractions and from a specified N. */
numeric digits 999; w=length(digits()) /*be able to handle gihugeic numbers. */
parse arg N terms fracs /*obtain optional arguments from the CL*/
if N=='' | N=="," then N=2 /*Not specified? Then use the default.*/
if terms=='' | terms=="," then terms=100 /* " " " " " " */
if fracs='' then fracs= '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'
/* [↑] The default for the fractions. */
f=space(fracs, 0) /*remove all blanks from the FRACS list*/
do #=1 while f\==''; parse var f n.# '/' d.# "," f
end /*#*/ /* [↑] parse all the fractions in list*/
#=#-1 /*adjust the number of fractions found.*/
tell= terms>0 /*flag: show number or a power of 2.*/
!.=0; _=1 /*the default value for powers of 2. */
if \tell then do p=1 until length(_)>digits(); _=_+_; !._=1
if p==1 then @._=left('',w+9) "2**"left(p,w) ' '
else @._='(prime' right(p,w)") 2**"left(p,w) ' '
end /*p*/ /* [↑] build powers of 2 tables.*/
#=i-1 /*the number of fractions found. */
say # 'fractions:' fracs /*display # and actual fractions.*/
say 'N is starting at ' N /*display the starting number N.*/
if tell then say terms ' terms are being shown:' /*display hdr.*/
else say 'only powers of two are being shown:' /* " " */
q='(max digits used: ' /*a literal used in the SAY below*/
end /*p*/ /* [↑] build powers of 2 tables. */
L=length(N) /*length in decimal digits of integer N*/
say # 'fractions:' fracs /*display number and actual fractions. */
say 'N is starting at ' N /*display the starting number N. */
if tell then say terms ' terms are being shown:' /*display hdr.*/
else say 'only powers of two are being shown:' /* " " */
q='(max digits used:' /*a literal used in the SAY below. */
do j=1 for abs(terms) /*perform loop once for each term*/
do k=1 for #; if N//d.k\==0 then iterate /*not an integer?*/
if tell then say right('term' j,35) ' ' N /*display Nth term&N*/
else if !.N then say right('term' j,15) '' @.N q,
right(L,w)") " N /*2ⁿ.*/
N = N % d.k * n.k /*calculate the next term (use %)*/
L=max(L, length(N)) /*maximum number of decimal digs.*/
leave /*go start calculating next term.*/
end /*k*/ /* [↑] if integer, found a new N*/
end /*j*/
/*stick a fork in it, we're done.*/
do j=1 for abs(terms) /*perform DO loop once for each term. */
do k=1 for # /* " " " " " " fraction*/
if N//d.k\==0 then iterate /*Not an integer? Then ignore it. */
if tell then say right('term' j, 35) "──► " N /*display Nth term and N.*/
else if !.N then say right('term' j,15) "──►" @.N q right(L,w)") " N
N=N % d.k * n.k /*calculate next term (use %≡integer ÷)*/
L=max(L, length(N)) /*the maximum number of decimal digits.*/
iterate j /*go start calculating the next term. */
end /*k*/ /* [↑] if an integer, we found a new N*/
end /*j*/ /*stick a fork in it, we're done. */

View file

@ -1,5 +1,5 @@
str ="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"
FractalProgram = str.split(',').map(&:to_r) #=> array of rationals
str = %w[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]
FractalProgram = str.map(&:to_r) #=> array of rationals
Runner = Enumerator.new do |y|
num = 2
@ -14,5 +14,5 @@ prime_generator = Enumerator.new do |y|
end
# demo
p Runner.take(20)
p Runner.take(20).map(&:numerator)
p prime_generator.take(20)