123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- module decrep; % Periodic Decimal Representation.
- % Author: Lisa Temme
- % Date: August 1995.
- algebraic;
- % Procedure to check if an argument is a list.
- procedure paarp(x); lisp eqcar(x,'list);
- procedure tidy(u);
- % tidy {wholepart, {non_recursive_decimal_part},
- % {recursive_decimal_part}}
- % to {{num_non_per_part, den_non_per_part}, {recursive_decimal_part}}
- begin
- scalar a, b, b1, c, num_non_per_part, den_non_per_part;
-
- a := part(u,1);
- b := part(u,2);
- c := part(u,3); %recursive part
-
- if length(b)=0 then << b1 := 0 >>
- else b1 := digits2number(b);
- %%match -ve value
- if a<0
- then num_non_per_part :=a*(10^length(b)) - b1
- else num_non_per_part :=a*(10^length(b)) + b1;
- den_non_per_part := 10^length(b);
-
- return list(list(num_non_per_part, den_non_per_part), c)
- end;
- %******************
- procedure digits2number(x);
- %%convert an list of digits to a number
- begin
- scalar j, number, !*rounded, dmode!*;
- if x={} OR NOT(paarp x) %check for empty list OR non-list
- then rederr
- "argument of digits2number should be list of non-negative digits";
- number := part(x,1);
- for j:=1:(length(x)-1) do
- <<
- if (numberp(part(x,j)) and part(x,j)>0 and part(x,j)<10)
- OR part(x,j)=0
- then number := number*10 + part(x,j+1)
- else rederr
- "argument of digits2number should be list of non-negative digits"
- >>;
- return number
- end;
- procedure number2digits(n);
- %%convert a number to a list of digits
- begin
- scalar number, list_of_ints, tmp, next_number, flg,
- !*rounded, dmode!*;
- flg := 0;
- %%check for integer argument
- if NOT(fixp n) then
- rederr "argument must be an integer";
- %%match -ve Input => -ve Output
- if n<0 then << flg:=1; n:=-n >>;
- %%match zero Input => zero Output
- if n=0 then return {0}
- else list_of_ints := {};
- tmp := n;
- while tmp>0 do
- << next_number := remainder(tmp,10);
- list_of_ints := next_number.list_of_ints;
- tmp := (tmp - next_number)/10
- >>;
- %%match -ve Input => -ve Output
- if flg=1
- then return append(list(- first list_of_ints), rest list_of_ints)
- else return list_of_ints;
- % if flg=1 then return list("-",list_of_ints)
- % else return list_of_ints;
- end;
- %***********************
- operator periodic;
- procedure rational2periodic(xx);
- %%gives periodic decimal representation of integer division
- %%check to see if rounded switch is off
- if lisp !*rounded
- then rederr "operator to be used in off rounded mode"
- else
- <<begin
- scalar n, m, z, n_repr, answer, numerator, wholepart,
- nexttryresult, result, numb, remd, negflg,
- !*rounded, dmode!*;
- %%check for rational number argument
- if NOT(numberp xx)
- then rederr "argument must be a rational number";
- n := num xx;
- m := den xx;
- %%match -ve Input => -ve Output
- negflg := 0;
- if xx<0
- then
- << n_repr := append(list(- first number2digits(n)),
- rest number2digits(n));
- negflg := negflg + 1
- >>
- else n_repr := number2digits(n);
- %%calculate before decimal point
- answer := {};
- numerator := first(n_repr);
- while length(n_repr) >1 do
- <<
- n_repr := rest n_repr;
- answer := ((numerator - remainder(numerator, m))/m).answer;
- numerator := remainder(numerator, m) * 10 + first n_repr
- >>;
- answer := ((numerator - remainder(numerator, m))/m).answer ;
- wholepart := digits2number(reverse(answer));
-
- %%calculate first decimal digit
- numerator := remainder(numerator,m)*10;
- numb := (numerator - remainder(numerator, m))/m;
- remd := remainder(numerator, m);
- z := {};
- numerator := remd*10;
- %%calculate decimal part & check for recursion
- while length(nexttry(numb, remd, z)) neq 2
- do
- << z := {numb, remd}.z;
- numb := (numerator - remainder(numerator, m))/m;
- remd := remainder(numerator,m);
- numerator := remd*10;
- >>;
- %%nexttry returns either {} or {decimal_ans, recurrence}
- nexttryresult := nexttry(numb, remd, z);
- %%put result in form
- %% { {numerator non-periodic part, denominator non-periodic part},
- %% {period} }
- %%match -ve Input => -ve Output
- if negflg neq 0
- then
- << if wholepart=0
- then
- << partresult := tidy(list(wholepart,
- first(nexttryresult),
- second(nexttryresult)));
- if length(first(nexttryresult))=0
- then
- << result := list(first first partresult,
- - second first partresult).
- rest partresult;
- >>
- else
- << result := list(-first first partresult,
- second first partresult).
- rest partresult
- >>;
- >>
- else
- << partresult := tidy(list(wholepart,
- first(nexttryresult),
- second(nexttryresult)));
- result := list(-first first partresult,
- second first partresult).
- rest partresult
- >>;
- >>
- else
- << result := tidy(list(wholepart,
- first(nexttryresult),
- second(nexttryresult)))
- >>;
- %return result;
- return periodic(first result, second result);
- end
- >>;
-
-
- procedure nexttry(x,y,z);
- %%compare {x,y} with z (the list of previous ordered pairs {x,y})
- begin
- scalar recurrence, decimal_ans, num_rem, ans, h, k, j,
- !*rounded, dmode!*; %added dmode!* here
- recurrence :={};
- decimal_ans := {};
- num_rem := {x,y};
- ans := {};
- h:=0;
- k := length(z);
- %%look through z to see if {x,y} has already occured
- while (k>0 and h=0) do
- <<
- if num_rem = part(z,k) then
- <<
- for j := 1:k do recurrence := first(part(z,j)).recurrence;
- for j := k+1:length(z)
- do decimal_ans := first(part(z,j)).decimal_ans;
- h:=1;
- >>;
- k := k-1;
- if h=1 then ans := list(decimal_ans,recurrence)
- >>;
-
- %%return list(decimal_ans,recurrence)
- return ans
- end;
- operator periodic2rational;
- %% Ruleset to allow two types of periodic input.
- per2ratRULES :=
- {
- periodic2rational(periodic(~x,~y)) => periodic2rational(x,y)
- when paarp x and length x=2
- and paarp y,
- periodic2rational(~x,~y) => per2rat(x,y)
- when paarp x and length x=2
- and paarp y
- };
- let per2ratRULES;
- %% Procedure to convert a periodic representation to a rational one.
- procedure per2rat(ab,c);
- %%check to see if rounded switch is off
- if lisp !*rounded
- then rederr "operator to be used in off rounded mode"
- else
- <<begin
- scalar a, b, number_c, power, fract;
- a := first ab;
- b := second ab;
- if a<0 then << a:=-a; b:=-b>>;
- if NOT(fixp b) OR
- ( (remainder(b,10) neq 0) AND (b neq 1) AND (b neq -1) )
- then rederr "denominator must be 1, -1 or a multiple of 10";
- if length c = 0 then number_c = 0
- else number_c := digits2number c;
-
- power := length c;
-
- fract := a/b + 1/b*(number_c/10^power*(1/(1-1/10^power)));
-
- return fract
-
- end
- >>;
- % printers
- symbolic procedure print_periodic (u);
- if not(!*nat) or
- (length caddr u + 10) > (linelength nil) then 'failed else
- begin scalar oo,x,intpart,intstring,l1,l2,perio,minussign;
- intpart := cdr cadr u;
- if cadr intpart= (-1) then
- << minussign := t; intpart := list (car intpart, 1)>>;
- if car intpart < 0 then
- << minussign := t;
- intpart := list (-(car intpart),cadr intpart)>>;
- intstring := explode car intpart;
- l1 := length intstring;
- l2 := length explode cadr intpart;
-
- perio := cdr caddr u;
- ycoord!* := ycoord!* +1;
- oo := posn!*;
- ymax!* := max(ymax!*,ycoord!*);
- x:= max(l1,l2);
- if minussign then x := x + 1;
- for i:=0:x do prin2!* " ";
- x := for each q in perio sum length explode q;
- if not(caddr u = '(list 0)) then
- for i:=1:x do prin2!* "_";
- posn!* := oo;
- ycoord!* := ycoord!* -1;
- if minussign then prin2!* "-";
- if l1 < l2 then <<l2 := l2 -1; prin2!* "0.">> else
- while l1 > 0 do <<
- prin2!* car intstring;
- intstring := cdr intstring;
- l1 := l1 -1;
- if l1 < l2 then << l1 := 0; l2 := l2 -1; prin2!* ".">>;
- >>;
- while l2 > 0 do <<
- if intstring then <<prin2!* car intstring;
- intstring := cdr intstring;>>
- else prin2!* '!0;
- l2 := l2 -1 >>;
- if not(caddr u = '(list 0)) then for each q in perio do prin2!* q;
- return t;
- end;
- put('periodic,'prifn,'print_periodic);
- endmodule;
- end;
|