/* Base conversion in Picat. Converting a number into an arbitrary base. Note: base/2 and unbase/2 are from from my module apl_util.pi but I wanted them in a program. This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ % import util. % import cp. main => go. go => % base println("base:"), base_test(BaseTest), foreach([Base,Digits] in BaseTest) println([base=Base,digits=Digits]), println(base=base(Base,Digits)), nl end, % unbase println("unbase:"), unbase_test(UnbaseTest), foreach([Base,Num] in UnbaseTest) println([base=Base,num=Num]), println(unbase=unbase(Base,Num)), nl end, nl, Radix = [1736,3,12], writeln(radix=Radix), writeln(unbase=unbase(Radix,10901)), writeln(unbase_base=base(Radix,unbase(Radix,10901))), nl, writeln(fibt=unbase([fibt(I):I in 1..25].reverse(),2**200)), nl. base_test(List) => List = [ % Base, Digits [[10,10,10,10],[4,1,2,3]], % decimal [10,[4,1,2,3]], % decimal [[2,2,2,2],[1,0,1,1]], % binary [2,[1,0,1,1]], % binary [[0,3,12],[3,0,1]], [[1736,3,12],[3,0,1]], [[24,60,60],[2,27,19]], [[7,24,60,60],[1,3,0,1]], % Day,Hours,Minutes,Seconds as Seconds [[100,1000,10,100],[35,681,7,24]] ]. unbase_test(List) => List = [ % Base , Num [[10,10,10,10],4123], % decimal [10,4123], [[2,2,2,2],11], % binary [2,11], [[24,60,60],8839], [[7,24,60,60],90721], [[24,60,60],123456] ]. % % Fibonacce (from exs.pi) % table fibt(0)=1. fibt(1)=1. fibt(N)=F,N>1 => F=fibt(N-1)+fibt(N-2). % % base(Radix,List) % % converts a List with radix list Radix to a number % % % decimal % Picat> base([10,10,10,10],[4,1,2,3])) % 4123 % Picat> base(10,[4,1,2,3])) % 4123 % % % Binary % Picat> base([2,2,2,2],[1,0,1,1])) % 11 % Picat> base(2,[1,0,1,1])) % 11 % % % These two are the same % Picat> base([0,3,12],[3,0,1])), % 109 % Picat> base([1736,3,12],[3,0,1])) % 109 % % % Hours,Minutes,Seconds % Picat base([24,60,60],[2,27,19])), % 8839 % % % Days,Hours,Minutes,Seconds as Seconds % Picat> base([7,24,60,60],[1,3,0,1])) % 90721 % % (This was inspired from APL base function (and K's _sv function) % % When N is an integer: Radix = [N,N,N,...,N] base(N,List) = base([N : _I in 1..List.length],List), integer(N) => true. % Radix is a list base(Radix,List) = S, list(Radix) => S = sum([E*R :{R,E} in zip(Radix.cumprod_base().reverse(),List)]). % cumulative product (special for base) private cumprod_base(List) = C => One = 1, C = [One], Len = List.length, foreach(I in Len..-1..2) One := One * List[I], C := C ++ [One] end. % unbase(Radix, N) % % This is the reverse of base(Radix,N), i.e. % convert the the number N to "radix slots" % % Picat> unbase([10,10,10,10], 1234) % [1,2,3,4] % Picat> unbase(10, 1234) % [1,2,3,4] % % Picat> unbase([24,60,60], 12345) % [3,25,45] % % We add an extra element if the value is too large % % Picat> unbase([24,60,60], 123456) % [1,10,17,36] % % Picat> unbase([24,60,60], 3) % [3] % % Picat> unbase([fibt(I):I in 1..25].reverse(),2**200) % [8,43367,7198,15921,1340,2912,1090,3499,1367,137,76,245,164,98,109,76,49,0,0,1,0,2,2,0,0] % % % This was inspired by APL's unbase and K's _vs % % Radix (N) is an integer unbase(N, Val) = reverse(List), integer(N) => List = [], V = Val, while(V > 0) List := List ++ [V mod N], V := V div N end, if V > 0 then List := List ++ [V] end. % Radix is a list unbase(Radix, Val) = reverse(List), list(Radix) => List = [], V = Val, foreach(R in Radix.reverse(), V > 0) List := List ++ [V mod R], V := V div R end, if V > 0 then List := List ++ [V] end.