numeval.red 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. module numeval; % numeric evaluation of algebraic expressions.
  2. % Control of accuracy and precision.
  3. %
  4. % precision: number of digits used for computation,
  5. % accuracy: target precision of the results;
  6. %
  7. % precision might be modified automatically for reaching the
  8. % desired accuracy.
  9. symbolic procedure accuracycontrol(u,da,di);
  10. % u is an evaluated parameter list. Extract
  11. % accuracy and iterations. If not present, take
  12. % given default values.
  13. begin scalar x,n,v;
  14. v:=u;
  15. accuracy!*:=da; iterations!*:=di;
  16. while v do
  17. <<x:=car v; v:= cdr v;
  18. if eqcar(x,'equal) and cadr x memq'(accuracy iterations) then
  19. <<u:=delete(x,u); n:=caddr x;
  20. if cadr x='accuracy then accuracy!*:=n
  21. else iterations!*:=n;
  22. >>>>;
  23. return u;
  24. end;
  25. symbolic procedure update!-precision l;
  26. % l is a list of domain elements. IF the minimum of their absolute
  27. % values is smaller than 10**(precision*+3), the precision is
  28. % increased.
  29. begin scalar mn; integer zp,p;
  30. mn:=update!-precision1 l; % positive minimum.
  31. if null mn then return nil;
  32. p := precision 0; zp:=!:recip expt(10,p-3);
  33. dm!: <<
  34. if mn>zp then return nil;
  35. while mn<zp do <<p:=p+1;zp:=zp/10>>;
  36. >>;
  37. precmsg p;
  38. end;
  39. symbolic procedure update!-precision1 l;
  40. dm!:( begin scalar x,y,z;
  41. while l do
  42. <<x:=car l; l:=cdr l;
  43. if not zerop x then
  44. <<y:=abs x; z:=if null z or y<z then y else z>>
  45. >>;
  46. return z;
  47. end );
  48. % Switching of mode and introduction of specific simplifiction
  49. % rules.
  50. algebraic<<
  51. rules_rd :=
  52. {~u ** ~x => exp(log u * x) when not numberp x};
  53. procedure switch!-mode!-rd!-alg u;
  54. if u=0 then
  55. <<for all x clear exp x;
  56. let rules_rd;
  57. >> else <<
  58. for all x let exp x=e**x;
  59. clearrules rules_rd; >>;
  60. >>;
  61. symbolic procedure switch!-mode!-rd u;
  62. begin scalar oldmode,prec,ne;
  63. if null u then
  64. <<if not memq(dmode!*,'(!:rd!: !:cr))then
  65. <<oldmode:=t; setdmode('rounded,t)>>;
  66. ne := !*noequiv;
  67. !*noequiv:=t; prec:=precision 0;
  68. switch!-mode!-rd!-alg 0;
  69. return list(oldmode,prec,!*roundbf,ne)
  70. >> else <<
  71. if car u then setdmode('rounded,nil);
  72. precision cadr u;
  73. !*roundbf := caddr u;
  74. !*noequiv := cadddr u;
  75. switch!-mode!-rd!-alg 1;
  76. >>;
  77. end;
  78. % Support for the numerical (=domain specific) evaluation of
  79. % algebraic equations.
  80. %
  81. % Roughly equivalent:
  82. % evaluate(u,v,p) = numr subsq(simp u,pair(v,p))
  83. % but avoiding resimplification as we know that all components
  84. % must evaluate to domain elements.
  85. fluid '(dmarith!* !*evaluateerror);
  86. dmarith!*:= '(
  87. (difference . !:difference) (quotient . !:!:quotient)
  88. (minus . negf) (sqrt . num!-sqrtf)
  89. (expt . !:dmexpt) (min . dm!:min) (max . dm!:max));
  90. symbolic procedure evaluate(u,v,p);
  91. begin scalar a,r,!*evaluateerror,msg;
  92. msg := not !*protfg;
  93. a:= pair(v,p);
  94. r := errorset(list('evaluate0,mkquote u,mkquote a),msg,nil)
  95. where !*msg=nil,!*protfg=t;
  96. if errorp r then rederr
  97. "error during function evaluation (e.g. singularity)";
  98. return car r;
  99. end;
  100. symbolic procedure evaluate!*(u,v,p);
  101. % same as evaluate, but returning arithmetic (but not syntactical)
  102. % errors to the caller like errorset.
  103. begin scalar a,r,!*evaluateerror;
  104. a:= pair(v,p);
  105. r := errorset(list('evaluate0,mkquote u,mkquote a),nil,nil)
  106. where !*msg=nil,!*protfg=t;
  107. erfg!* := nil;
  108. if null !*evaluateerror then return r else
  109. evaluate0(u,a); % once more, but unprotected.
  110. end;
  111. symbolic procedure evaluate0(u,v);
  112. evaluate1(evaluate!-horner u,v);
  113. symbolic procedure evaluate1(u,v);
  114. if numberp u or null u then force!-to!-dm u else
  115. if pairp u and get(car u,'dname) then u else
  116. (if a then cdr a else
  117. if atom u then
  118. if u='i then
  119. if (u:=get(dmode!*,'ivalue)) then numr apply(u,'(nil))
  120. else rederr "i used as indeterminate value"
  121. else if u='e or u='pi then force!-to!-dm numr simp u
  122. else <<!*evaluateerror:=t; typerr(u,"number")>>
  123. else evaluate2(car u,cdr u,v)
  124. ) where a=assoc(u,v);
  125. symbolic procedure evaluate2(op,pars,v);
  126. if op='!:dn!: then numr dn!:simp pars else
  127. <<pars:=for each p in pars collect evaluate1(p,v);
  128. % arithmetic operator.
  129. if op='plus then !:dmpluslst pars else
  130. if op='times then !:dmtimeslst pars else
  131. if(a:=assoc(op,dmarith!*)) then apply(cdr a,pars) else
  132. % elementary function, applicable for current dmode.
  133. if pairp car pars and (a:=get(op,caar pars)) then
  134. apply(a,pars) else
  135. % apply REDUCE simplifier otherwise
  136. force!-to!-dm numr simp (op . for each p in pars collect prepf p)
  137. >> where a=nil;
  138. symbolic procedure list!-evaluate(u,v,p);
  139. for each r in u collect evaluate(r,v,p);
  140. symbolic procedure matrix!-evaluate(u,v,p);
  141. for each r in u collect list!-evaluate(r,v,p);
  142. symbolic procedure !:dmexpt(u,v);
  143. (if fixp n then !:expt(u,n) else
  144. <<u:=force!-to!-dm u; v:=force!-to!-dm v;
  145. if !*complex then crexpt!*(u,v) else rdexpt!*(u,v)
  146. >>) where n=!:dm2fix v;
  147. symbolic procedure dm!:min(a,b);
  148. dm!:(if a > b then b else a);
  149. symbolic procedure dm!:max(a,b);
  150. dm!:(if a > b then a else b);
  151. symbolic procedure !:dm2fix u;
  152. if fixp u then u else
  153. (if fixp(u:=int!-equiv!-chk u) then u else
  154. if null u then 0 else
  155. if floatp cdr u and 0.0=cdr u-fix cdr u then fix cdr u
  156. else u) where !*noequiv=nil;
  157. symbolic procedure !:dmtimeslst u;
  158. if null u then 1 else
  159. if null cdr u then car u else
  160. dm!:(car u * !:dmtimeslst cdr u);
  161. symbolic procedure !:dmpluslst u;
  162. if null u then 0 else
  163. if null cdr u then car u else
  164. dm!:(car u + !:dmpluslst cdr u);
  165. symbolic procedure !:!:quotient(u,v);
  166. !:quotient(u,if fixp v then i2rd!* v else v);
  167. % vector/matrix arithmetic
  168. symbolic procedure list!+list(l1,l2);
  169. if null l1 then nil else
  170. dm!: (car l1 + car l2) . list!+list(cdr l1,cdr l2);
  171. symbolic procedure list!-list(l1,l2);
  172. if null l1 then nil else
  173. dm!: (car l1 - car l2) . list!-list(cdr l1,cdr l2);
  174. symbolic procedure scal!*list(s,l);
  175. if null l then nil else
  176. dm!: (s * car l) . scal!*list(s,cdr l) ;
  177. symbolic procedure innerprod(u,v);
  178. if null u then 0 else
  179. dm!: ( car u * car v + innerprod(cdr u,cdr v) );
  180. symbolic procedure conjlist u;
  181. dm!:(if not !*complex then u else
  182. for each x in u collect
  183. repartf x - numr apply(get(dmode!*,'ivalue),'(nil))*impartf x );
  184. symbolic procedure normlist u;
  185. dm!:(sqrt innerprod(u, conjlist u));
  186. symbolic procedure mat!*list(m,v);
  187. if null cdr m then scal!*list(car v,car m) else
  188. for each r in m collect innerprod(r,v);
  189. symbolic procedure num!-sqrtf a;
  190. if domainp a then
  191. apply(get('sqrt,dmode!*),list force!-to!-dm a)
  192. else
  193. <<a:=simpsqrt list prepf a;
  194. if not onep denr a or not domainp numr a
  195. then rederr "sqrtf called in wrong mode"
  196. else numr a>>;
  197. symbolic procedure force!-to!-dm a;
  198. if not domainp a then typerr(prepf a,"number") else
  199. if null a then force!-to!-dm 0 else
  200. if numberp a then apply(get(dmode!*,'i2d),list a) else
  201. if pairp a and car a = dmode!* then a else
  202. (if fcn then apply(fcn,list a) else
  203. rederr list("conversion error with ",a)
  204. ) where fcn=(pairp a and get(car a,dmode!*));
  205. symbolic procedure printsflist(x);
  206. begin integer n;
  207. writepri("(",nil);
  208. for each y in x do
  209. <<if n>0 then writepri(" , ",nil);
  210. n:=n+1;
  211. writepri(mkquote prepf y,nil)>>;
  212. writepri(")",nil);
  213. end;
  214. fluid '(horner!-cache!*);
  215. symbolic procedure evaluate!-horner u;
  216. (if w then cdr w else
  217. <<w:=simp!* u;
  218. w:=prepsq(hornerf numr w ./ hornerf denr w);
  219. horner!-cache!* := (u.w). horner!-cache!*;
  220. w
  221. >>) where w=assoc(u,horner!-cache!*);
  222. endmodule;
  223. end;