2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -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 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.
|
||||
|
||||
* [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>
|
||||
|
|
|
|||
74
Task/Fractran/ALGOL-68/fractran.alg
Normal file
74
Task/Fractran/ALGOL-68/fractran.alg
Normal 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
|
||||
66
Task/Fractran/Elixir/fractran.elixir
Normal file
66
Task/Fractran/Elixir/fractran.elixir
Normal 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}"
|
||||
59
Task/Fractran/Erlang/fractran.erl
Normal file
59
Task/Fractran/Erlang/fractran.erl
Normal 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).
|
||||
2
Task/Fractran/Fortran/fractran-1.f
Normal file
2
Task/Fractran/Fortran/fractran-1.f
Normal 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.
|
||||
49
Task/Fractran/Fortran/fractran-2.f
Normal file
49
Task/Fractran/Fortran/fractran-2.f
Normal 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!
|
||||
11
Task/Fractran/Fortran/fractran-3.f
Normal file
11
Task/Fractran/Fortran/fractran-3.f
Normal 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.
|
||||
188
Task/Fractran/Fortran/fractran-4.f
Normal file
188
Task/Fractran/Fortran/fractran-4.f
Normal 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!
|
||||
5
Task/Fractran/Fortran/fractran-5.f
Normal file
5
Task/Fractran/Fortran/fractran-5.f
Normal 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.
|
||||
|
|
@ -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
|
||||
1
Task/Fractran/Haskell/fractran-2.hs
Normal file
1
Task/Fractran/Haskell/fractran-2.hs
Normal file
|
|
@ -0,0 +1 @@
|
|||
import Data.List.Split (splitOn)
|
||||
3
Task/Fractran/Haskell/fractran-3.hs
Normal file
3
Task/Fractran/Haskell/fractran-3.hs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
readProgram :: String -> [Ratio a]
|
||||
readProgram = map (toFrac . splitOn "/") . splitOn ","
|
||||
where toFrac [n,d] = read n % read d
|
||||
1
Task/Fractran/Haskell/fractran-4.hs
Normal file
1
Task/Fractran/Haskell/fractran-4.hs
Normal file
|
|
@ -0,0 +1 @@
|
|||
import Data.Maybe (mapMaybe)
|
||||
6
Task/Fractran/Haskell/fractran-5.hs
Normal file
6
Task/Fractran/Haskell/fractran-5.hs
Normal 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)
|
||||
43
Task/Fractran/OCaml/fractran.ocaml
Normal file
43
Task/Fractran/OCaml/fractran.ocaml
Normal 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
|
||||
15
Task/Fractran/PARI-GP/fractran.pari
Normal file
15
Task/Fractran/PARI-GP/fractran.pari
Normal 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));
|
||||
}
|
||||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue