decrep.red 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. module decrep; % Periodic Decimal Representation.
  2. % Author: Lisa Temme
  3. % Date: August 1995.
  4. algebraic;
  5. % Procedure to check if an argument is a list.
  6. procedure paarp(x); lisp eqcar(x,'list);
  7. procedure tidy(u);
  8. % tidy {wholepart, {non_recursive_decimal_part},
  9. % {recursive_decimal_part}}
  10. % to {{num_non_per_part, den_non_per_part}, {recursive_decimal_part}}
  11. begin
  12. scalar a, b, b1, c, num_non_per_part, den_non_per_part;
  13. a := part(u,1);
  14. b := part(u,2);
  15. c := part(u,3); %recursive part
  16. if length(b)=0 then << b1 := 0 >>
  17. else b1 := digits2number(b);
  18. %%match -ve value
  19. if a<0
  20. then num_non_per_part :=a*(10^length(b)) - b1
  21. else num_non_per_part :=a*(10^length(b)) + b1;
  22. den_non_per_part := 10^length(b);
  23. return list(list(num_non_per_part, den_non_per_part), c)
  24. end;
  25. %******************
  26. procedure digits2number(x);
  27. %%convert an list of digits to a number
  28. begin
  29. scalar j, number, !*rounded, dmode!*;
  30. if x={} OR NOT(paarp x) %check for empty list OR non-list
  31. then rederr
  32. "argument of digits2number should be list of non-negative digits";
  33. number := part(x,1);
  34. for j:=1:(length(x)-1) do
  35. <<
  36. if (numberp(part(x,j)) and part(x,j)>0 and part(x,j)<10)
  37. OR part(x,j)=0
  38. then number := number*10 + part(x,j+1)
  39. else rederr
  40. "argument of digits2number should be list of non-negative digits"
  41. >>;
  42. return number
  43. end;
  44. procedure number2digits(n);
  45. %%convert a number to a list of digits
  46. begin
  47. scalar number, list_of_ints, tmp, next_number, flg,
  48. !*rounded, dmode!*;
  49. flg := 0;
  50. %%check for integer argument
  51. if NOT(fixp n) then
  52. rederr "argument must be an integer";
  53. %%match -ve Input => -ve Output
  54. if n<0 then << flg:=1; n:=-n >>;
  55. %%match zero Input => zero Output
  56. if n=0 then return {0}
  57. else list_of_ints := {};
  58. tmp := n;
  59. while tmp>0 do
  60. << next_number := remainder(tmp,10);
  61. list_of_ints := next_number.list_of_ints;
  62. tmp := (tmp - next_number)/10
  63. >>;
  64. %%match -ve Input => -ve Output
  65. if flg=1
  66. then return append(list(- first list_of_ints), rest list_of_ints)
  67. else return list_of_ints;
  68. % if flg=1 then return list("-",list_of_ints)
  69. % else return list_of_ints;
  70. end;
  71. %***********************
  72. operator periodic;
  73. procedure rational2periodic(xx);
  74. %%gives periodic decimal representation of integer division
  75. %%check to see if rounded switch is off
  76. if lisp !*rounded
  77. then rederr "operator to be used in off rounded mode"
  78. else
  79. <<begin
  80. scalar n, m, z, n_repr, answer, numerator, wholepart,
  81. nexttryresult, result, numb, remd, negflg,
  82. !*rounded, dmode!*;
  83. %%check for rational number argument
  84. if NOT(numberp xx)
  85. then rederr "argument must be a rational number";
  86. n := num xx;
  87. m := den xx;
  88. %%match -ve Input => -ve Output
  89. negflg := 0;
  90. if xx<0
  91. then
  92. << n_repr := append(list(- first number2digits(n)),
  93. rest number2digits(n));
  94. negflg := negflg + 1
  95. >>
  96. else n_repr := number2digits(n);
  97. %%calculate before decimal point
  98. answer := {};
  99. numerator := first(n_repr);
  100. while length(n_repr) >1 do
  101. <<
  102. n_repr := rest n_repr;
  103. answer := ((numerator - remainder(numerator, m))/m).answer;
  104. numerator := remainder(numerator, m) * 10 + first n_repr
  105. >>;
  106. answer := ((numerator - remainder(numerator, m))/m).answer ;
  107. wholepart := digits2number(reverse(answer));
  108. %%calculate first decimal digit
  109. numerator := remainder(numerator,m)*10;
  110. numb := (numerator - remainder(numerator, m))/m;
  111. remd := remainder(numerator, m);
  112. z := {};
  113. numerator := remd*10;
  114. %%calculate decimal part & check for recursion
  115. while length(nexttry(numb, remd, z)) neq 2
  116. do
  117. << z := {numb, remd}.z;
  118. numb := (numerator - remainder(numerator, m))/m;
  119. remd := remainder(numerator,m);
  120. numerator := remd*10;
  121. >>;
  122. %%nexttry returns either {} or {decimal_ans, recurrence}
  123. nexttryresult := nexttry(numb, remd, z);
  124. %%put result in form
  125. %% { {numerator non-periodic part, denominator non-periodic part},
  126. %% {period} }
  127. %%match -ve Input => -ve Output
  128. if negflg neq 0
  129. then
  130. << if wholepart=0
  131. then
  132. << partresult := tidy(list(wholepart,
  133. first(nexttryresult),
  134. second(nexttryresult)));
  135. if length(first(nexttryresult))=0
  136. then
  137. << result := list(first first partresult,
  138. - second first partresult).
  139. rest partresult;
  140. >>
  141. else
  142. << result := list(-first first partresult,
  143. second first partresult).
  144. rest partresult
  145. >>;
  146. >>
  147. else
  148. << partresult := tidy(list(wholepart,
  149. first(nexttryresult),
  150. second(nexttryresult)));
  151. result := list(-first first partresult,
  152. second first partresult).
  153. rest partresult
  154. >>;
  155. >>
  156. else
  157. << result := tidy(list(wholepart,
  158. first(nexttryresult),
  159. second(nexttryresult)))
  160. >>;
  161. %return result;
  162. return periodic(first result, second result);
  163. end
  164. >>;
  165. procedure nexttry(x,y,z);
  166. %%compare {x,y} with z (the list of previous ordered pairs {x,y})
  167. begin
  168. scalar recurrence, decimal_ans, num_rem, ans, h, k, j,
  169. !*rounded, dmode!*; %added dmode!* here
  170. recurrence :={};
  171. decimal_ans := {};
  172. num_rem := {x,y};
  173. ans := {};
  174. h:=0;
  175. k := length(z);
  176. %%look through z to see if {x,y} has already occured
  177. while (k>0 and h=0) do
  178. <<
  179. if num_rem = part(z,k) then
  180. <<
  181. for j := 1:k do recurrence := first(part(z,j)).recurrence;
  182. for j := k+1:length(z)
  183. do decimal_ans := first(part(z,j)).decimal_ans;
  184. h:=1;
  185. >>;
  186. k := k-1;
  187. if h=1 then ans := list(decimal_ans,recurrence)
  188. >>;
  189. %%return list(decimal_ans,recurrence)
  190. return ans
  191. end;
  192. operator periodic2rational;
  193. %% Ruleset to allow two types of periodic input.
  194. per2ratRULES :=
  195. {
  196. periodic2rational(periodic(~x,~y)) => periodic2rational(x,y)
  197. when paarp x and length x=2
  198. and paarp y,
  199. periodic2rational(~x,~y) => per2rat(x,y)
  200. when paarp x and length x=2
  201. and paarp y
  202. };
  203. let per2ratRULES;
  204. %% Procedure to convert a periodic representation to a rational one.
  205. procedure per2rat(ab,c);
  206. %%check to see if rounded switch is off
  207. if lisp !*rounded
  208. then rederr "operator to be used in off rounded mode"
  209. else
  210. <<begin
  211. scalar a, b, number_c, power, fract;
  212. a := first ab;
  213. b := second ab;
  214. if a<0 then << a:=-a; b:=-b>>;
  215. if NOT(fixp b) OR
  216. ( (remainder(b,10) neq 0) AND (b neq 1) AND (b neq -1) )
  217. then rederr "denominator must be 1, -1 or a multiple of 10";
  218. if length c = 0 then number_c = 0
  219. else number_c := digits2number c;
  220. power := length c;
  221. fract := a/b + 1/b*(number_c/10^power*(1/(1-1/10^power)));
  222. return fract
  223. end
  224. >>;
  225. % printers
  226. symbolic procedure print_periodic (u);
  227. if not(!*nat) or
  228. (length caddr u + 10) > (linelength nil) then 'failed else
  229. begin scalar oo,x,intpart,intstring,l1,l2,perio,minussign;
  230. intpart := cdr cadr u;
  231. if cadr intpart= (-1) then
  232. << minussign := t; intpart := list (car intpart, 1)>>;
  233. if car intpart < 0 then
  234. << minussign := t;
  235. intpart := list (-(car intpart),cadr intpart)>>;
  236. intstring := explode car intpart;
  237. l1 := length intstring;
  238. l2 := length explode cadr intpart;
  239. perio := cdr caddr u;
  240. ycoord!* := ycoord!* +1;
  241. oo := posn!*;
  242. ymax!* := max(ymax!*,ycoord!*);
  243. x:= max(l1,l2);
  244. if minussign then x := x + 1;
  245. for i:=0:x do prin2!* " ";
  246. x := for each q in perio sum length explode q;
  247. if not(caddr u = '(list 0)) then
  248. for i:=1:x do prin2!* "_";
  249. posn!* := oo;
  250. ycoord!* := ycoord!* -1;
  251. if minussign then prin2!* "-";
  252. if l1 < l2 then <<l2 := l2 -1; prin2!* "0.">> else
  253. while l1 > 0 do <<
  254. prin2!* car intstring;
  255. intstring := cdr intstring;
  256. l1 := l1 -1;
  257. if l1 < l2 then << l1 := 0; l2 := l2 -1; prin2!* ".">>;
  258. >>;
  259. while l2 > 0 do <<
  260. if intstring then <<prin2!* car intstring;
  261. intstring := cdr intstring;>>
  262. else prin2!* '!0;
  263. l2 := l2 -1 >>;
  264. if not(caddr u = '(list 0)) then for each q in perio do prin2!* q;
  265. return t;
  266. end;
  267. put('periodic,'prifn,'print_periodic);
  268. endmodule;
  269. end;