125 lines
3.6 KiB
Plaintext
125 lines
3.6 KiB
Plaintext
ratio = cluster is new, parse, unparse, get_num, get_denom, mul
|
|
rep = struct[num, denom: int]
|
|
|
|
new = proc (num, denom: int) returns (cvt)
|
|
return(simplify(rep${num: num, denom: denom}))
|
|
end new
|
|
|
|
parse = proc (rat: string) returns (ratio) signals (bad_format)
|
|
rat := trim(rat)
|
|
sep: int := string$indexc('/', rat)
|
|
if sep = 0 then signal bad_format end
|
|
|
|
num: string := string$substr(rat, 1, sep-1)
|
|
denom: string := string$rest(rat, sep+1)
|
|
return(new(int$parse(num), int$parse(denom))) resignal bad_format
|
|
end parse
|
|
|
|
trim = proc (s: string) returns (string)
|
|
start: int := 1
|
|
while start <= string$size(s) cand s[start] = ' ' do start := start + 1 end
|
|
|
|
end_: int := string$size(s)
|
|
while end_ >= 1 cand s[end_] = ' ' do end_ := end_ - 1 end
|
|
return(string$substr(s, start, end_-start+1))
|
|
end trim
|
|
|
|
unparse = proc (rat: cvt) returns (string)
|
|
return(int$unparse(rat.num) || "/" || int$unparse(rat.denom))
|
|
end unparse
|
|
|
|
get_num = proc (rat: cvt) returns (int)
|
|
return(rat.num)
|
|
end get_num
|
|
|
|
get_denom = proc (rat: cvt) returns (int)
|
|
return(rat.denom)
|
|
end get_denom
|
|
|
|
mul = proc (a, b: cvt) returns (ratio)
|
|
return(new(a.num * b.num, a.denom * b.denom))
|
|
end mul
|
|
|
|
simplify = proc (rat: rep) returns (rep)
|
|
num: int := int$abs(rat.num)
|
|
denom: int := int$abs(rat.denom)
|
|
|
|
sign: int
|
|
if (rat.num < 0) = (rat.denom < 0)
|
|
then sign := 1
|
|
else sign := -1
|
|
end
|
|
|
|
factor: int := gcd(num, denom)
|
|
return(rep${num: sign*num/factor, denom: denom/factor})
|
|
end simplify
|
|
|
|
gcd = proc (a, b: int) returns (int)
|
|
while b ~= 0 do
|
|
a, b := b, a // b
|
|
end
|
|
return(a)
|
|
end gcd
|
|
end ratio
|
|
|
|
fractran = cluster is parse, run
|
|
rep = sequence[ratio]
|
|
|
|
parse = proc (program: string) returns (cvt)
|
|
parsed: array[ratio] := array[ratio]$[]
|
|
for rat: ratio in ratioes(program) do
|
|
array[ratio]$addh(parsed, rat)
|
|
end
|
|
return(rep$a2s(parsed))
|
|
end parse
|
|
|
|
ratioes = iter (program: string) yields (ratio)
|
|
while true do
|
|
sep: int := string$indexc(',', program)
|
|
if sep = 0 then
|
|
yield(ratio$parse(program))
|
|
break
|
|
else
|
|
yield(ratio$parse(string$substr(program, 1, sep-1)))
|
|
program := string$rest(program, sep+1)
|
|
end
|
|
end
|
|
end ratioes
|
|
|
|
run = iter (program: cvt, n, maxiter: int) yields (int)
|
|
nrat: ratio := ratio$new(n, 1)
|
|
while maxiter > 0 do
|
|
yield(nrat.num)
|
|
begin
|
|
for rat: ratio in rep$elements(program) do
|
|
mul: ratio := rat * nrat
|
|
if mul.denom = 1 then
|
|
exit found(mul)
|
|
end
|
|
end
|
|
break
|
|
end except when found(new: ratio):
|
|
nrat := new
|
|
end
|
|
maxiter := maxiter - 1
|
|
end
|
|
end run
|
|
end fractran
|
|
|
|
start_up = proc ()
|
|
po: stream := stream$primary_output()
|
|
|
|
program: string := "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"
|
|
parsed: fractran := fractran$parse(program)
|
|
|
|
index: int := 0
|
|
for result: int in fractran$run(parsed, 2, 20) do
|
|
stream$putright(po, int$unparse(index), 3)
|
|
stream$putc(po, ':')
|
|
stream$putright(po, int$unparse(result), 10)
|
|
stream$putl(po, "")
|
|
index := index + 1
|
|
end
|
|
end start_up
|