plotnum.red 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. module plotnum; % Numeric evaluation of algebraic expressions.
  2. fluid '(plotsynerr!* ploteval!-alist2!*);
  3. global '(!*plotinterrupts);
  4. flag('(plus plus2 difference times times2 quotient exp expt expt!-int
  5. % minus sin cos tan cot asin acos acot atan log),'plotevallisp);
  6. minus sin cos tan cot asin acos acot atan abs log),'plotevallisp);
  7. symbolic procedure plotrounded d;
  8. % Switching rounded mode safely on and off.
  9. begin scalar o,!*protfg,c,r,!*msg;
  10. !*protfg:=t;
  11. if null d then
  12. <<c:=!*complex; r:=!*rounded;
  13. if c then <<setdmode('complex,nil); !*complex := nil>>;
  14. if not r and dmode!* then
  15. <<o:=get(dmode!*,'dname); setdmode(o,nil)>>;
  16. o:={o,r,!*roundbf,c,precision 0};
  17. if not r then <<!*rounded:=t; setdmode('rounded,t)>>;
  18. !*roundbf:=nil;
  19. if c then <<setdmode('complex,t); !*complex := t>>;
  20. return o;
  21. >>
  22. else
  23. <<
  24. % reconstruct the previous configuration.
  25. if !*complex then setdmode('complex,nil);
  26. if null(!*rounded:=cadr d) then setdmode('rounded,nil);
  27. !*roundbf:=caddr d;
  28. if car(d) then setdmode(car d,t);
  29. if !*complex then setdmode('complex,t);
  30. precision car cddddr d;
  31. >>;
  32. end;
  33. symbolic procedure adomainp u;
  34. % numberp test in an algebraic form.
  35. numberp u or (pairp u and idp car u and get(car u,'dname))
  36. or eqcar(u,'minus) and adomainp cadr u;
  37. symbolic procedure revalnuminterval(u,num);
  38. % Evaluate u as interval; numeric bounds required if num=T.
  39. begin scalar l;
  40. if not eqcar(u,'!*interval!*) then typerr(u,"interval");
  41. l:={reval cadr u,reval caddr u};
  42. if null num or(adomainp car l and adomainp cadr l)then return l;
  43. typerr(u,"numeric interval");
  44. end;
  45. ploteval!-alist2!*:={{'x . 1},{'y . 2}};
  46. symbolic procedure plot!-form!-prep(f,x,y);
  47. % f is a REDUCE function expression depending of x and y.
  48. % Compute a form which allows me to evaluate "f(x,y)" as
  49. % a LISP expr.
  50. {'lambda,'(!&1 !&2),
  51. {'plot!-form!-call2,mkquote rdwrap f,mkquote f,
  52. mkquote x,'!&1,
  53. mkquote y,'!&2}};
  54. symbolic procedure plot!-form!-call2(ff,f,x,x0,y,y0);
  55. % Here I hack into the statically allocated a-list in order
  56. % to save cons cells.
  57. begin scalar a;
  58. a:=car ploteval!-alist2!*;
  59. car a := x; cdr a := x0;
  60. a:=cadr ploteval!-alist2!*;
  61. car a:= y; cdr a:= y0;
  62. return plotevalform(ff,f,ploteval!-alist2!*);
  63. end;
  64. % The following routines are used to transform a REDUCE algebraic
  65. % expression into a form which can be evaluated directly in LISP.
  66. symbolic procedure rdwrap f;
  67. begin scalar r,!*msg,!*protfg;
  68. !*protfg:=t;
  69. r:=errorset({'rdwrap1,mkquote f},nil,nil);
  70. return if errorp r then 'failed else car r;
  71. end;
  72. symbolic procedure rdwrap1 f;
  73. if numberp f then float f
  74. else if f='pi then 3.141592653589793238462643
  75. else if f='e then 2.7182818284590452353602987
  76. else if f='i and !*complex then rederr "i not LISP evaluable"
  77. else if atom f then f
  78. else if get(car f,'dname) then rdwrap!-dm f
  79. else if eqcar(f, 'MINUS) then
  80. begin scalar x;
  81. x := rdwrap1 cadr f;
  82. return if numberp x then minus float x else {'MINUS, x}
  83. end
  84. else if eqcar(f,'expt) then rdwrap!-expt f
  85. else
  86. begin scalar a,w;
  87. if null getd car f or not flagp(car f,'plotevallisp)
  88. then typerr(car f,"Lisp arithmetic function (warning)");
  89. a:=for each c in cdr f collect rdwrap1 c;
  90. if (w:=atsoc(car f,'((plus.plus2)(times.times2))))
  91. then return rdwrapn(cdr w,a);
  92. return car f . a;
  93. end;
  94. symbolic procedure rdwrapn(f,a);
  95. % Unfold a n-ary arithmetic call.
  96. if null cdr a then car a else {f,car a,rdwrapn(f,cdr a)};
  97. symbolic procedure rdwrap!-dm f;
  98. % f is a domain element.
  99. if car f eq '!:RD!: then
  100. if atom cdr f then cdr f else bf2flr f
  101. else if car f eq '!:CR!: then rdwrap!-cr f
  102. else if car f eq '!:GI!:
  103. then rdwrap!-cmplex(f,float cadr f,float cddr f)
  104. else if car f eq '!:DN!: then rdwrap2 cdr f
  105. else << plotsynerr!*:=t;
  106. rerror(PLOTPACKAGE, 32, {get(car f, 'DNAME),
  107. "illegal domain for PLOT"})
  108. >>;
  109. symbolic procedure rdwrap!-cr f;
  110. begin scalar re,im;
  111. re := cadr f;
  112. if not atom re then re := bf2flr re;
  113. im := cddr f;
  114. if not atom im then im := bf2flr im;
  115. return rdwrap!-cmplx(f,re,im);
  116. end;
  117. symbolic procedure rdwrap!-cmplx(f,re,im);
  118. if abs im * 1000.0 > abs re then typerr(f,"real number") else re;
  119. symbolic procedure plotrepart u;
  120. if car u eq '!:rd!: then u else
  121. if car u memq '(!:gi!: !:cr!:) then '!:rd!: . cadr u;
  122. symbolic procedure rdwrap!-expt f;
  123. % preserve integer second argument.
  124. if fixp caddr f then
  125. if caddr f>0 then {'expt!-int,rdwrap1 cadr f,caddr f}
  126. else {'quotient,1,{'expt!-int,rdwrap1 cadr f,-caddr f}}
  127. else {'expt,rdwrap1 cadr f, rdwrap caddr f};
  128. symbolic procedure rdwrap2 f;
  129. % Convert from domain to LISP evaluable value.
  130. if atom f then f else float car f * 10^cdr f;
  131. symbolic procedure rdwrap!* f;
  132. % convert a domain element to float.
  133. if null f then 0.0 else rdwrap f;
  134. symbolic procedure rdunwrap f;
  135. if f=0.0 then 0 else if f=1.0 then 1 else '!:rd!: . f;
  136. symbolic procedure expt!-int(a,b); expt(a,fix b);
  137. symbolic procedure plotevalform(ff,f,a);
  138. % ff is LISP evaluable,f REDUCE evaluable.
  139. begin scalar u,w,!*protfg,mn,r,!*msg;
  140. !*protfg := t;
  141. % if ff='failed then goto non_lisp;
  142. if ff eq 'failed or not atom ff and 'failed memq ff
  143. then goto non_lisp;
  144. % WN 12. May.97 plot(e^(abs x)); bombed
  145. u:= errorset({'plotevalform1,mkquote ff,mkquote a},nil,nil);
  146. if not ploterrorp u and numberp (u:=car u) then
  147. <<if abs u > plotmax!* then return plotoverflow plotmax!* else
  148. return u;
  149. >>;
  150. non_lisp:
  151. w := {'simp, mkquote
  152. sublis(
  153. for each p in a collect (car p.rdunwrap cdr p),
  154. f)};
  155. u := errorset(w,nil,nil);
  156. if ploterrorp u or (u:=car u) eq 'failed then return nil;
  157. if denr u neq 1 then return nil;
  158. u:=numr u;
  159. if null u then return 0; % Wn
  160. if numberp u then <<r:=float u; goto x>>;
  161. if not domainp u or not memq(car u,'(!:rd!: !:gi!: !:cr!:))
  162. then return nil;
  163. if evalgreaterp(plotrepart u, fl2rd plotmax!*) then
  164. return plotoverflow plotmax!* else
  165. if evalgreaterp(fl2rd (-plotmax!*),plotrepart u) then
  166. return plotoverflow (-plotmax!*);
  167. r:=errorset({'rdwrap!-dm,mkquote u},nil,nil);
  168. if errorp r or(r:=car r) eq 'failed then return nil;
  169. x: return if mn then -r else r;
  170. end;
  171. symbolic procedure plotoverflow u;
  172. <<if not !*plotoverflow then
  173. lprim "plot number range exceeded";
  174. !*plotoverflow := t;
  175. 'overflow . u
  176. >> where !*protfg = nil;
  177. symbolic procedure plotevalform0(f,a);
  178. (if ploterrorp u
  179. then typerr(f,"expression for plot") else car u)
  180. where u=
  181. errorset({'plotevalform1,mkquote f,mkquote a},nil,nil);
  182. %symbolic procedure plotevalform1(f,a);
  183. % begin scalar x,w;
  184. % if numberp f then return float f;
  185. % if (x:=assoc(f,a)) then return plotevalform1(cdr x,a);
  186. % if not atom f and flagp(car f,'plotevallisp) then
  187. % return eval
  188. % (car f . for each y in cdr f collect plotevalform1(y,a));
  189. % if not atom f then f :=
  190. % car f . for each y in cdr f collect prepf plotevalform2(y,a);
  191. % w:=simp f;
  192. % if denr w neq 1 or not domainp numr w then goto err;
  193. % return rdwrap!* numr w;
  194. % err:
  195. % plotsynerr!*:=t;
  196. % typerr(prepsq w,"numeric value");
  197. %end;
  198. symbolic procedure plotevalform1(f,a);
  199. begin scalar x;
  200. if numberp f then return float f;
  201. if (x:=assoc(f,a)) then return plotevalform1(cdr x,a);
  202. if atom f then go to err;
  203. return if cddr f then
  204. idapply(car f,{plotevalform1(cadr f,a),plotevalform1(caddr f,a)})
  205. else
  206. idapply(car f,{plotevalform1(cadr f,a)});
  207. err:
  208. plotsynerr!*:=t;
  209. typerr(prepsq f,"numeric value");
  210. end;
  211. %symbolic procedure plotevalform2(f,a);
  212. % begin scalar x,w;
  213. % if fixp f then return f;
  214. % if floatp f then return rdunwrap f;
  215. % if (x:=assoc(f,a)) then return plotevalform2(cdr x,a);
  216. % if not atom f and flagp(car f,'plotevallisp) then
  217. % return rdunwrap eval
  218. % (car f . for each y in cdr f collect plotevalform1(y,a));
  219. % if not atom f then f :=
  220. % car f . for each y in cdr f collect prepf plotevalform2(y,a);
  221. % w:=simp f;
  222. % if denr w neq 1 or not domainp numr w then goto err;
  223. % return numr w;
  224. % err:
  225. % plotsynerr!*:=t;
  226. % typerr(prepsq w,"numeric value");
  227. %end;
  228. symbolic procedure ploterrorp u;
  229. if u member !*plotinterrupts
  230. then rederr prin2 "***** plot killed"
  231. else atom u or cdr u;
  232. endmodule;
  233. end;