limits.red 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. module limits;
  2. %% A fast limit package for REDUCE for functions which are continuous
  3. %% except for computable poles and singularities.
  4. %% Author: Stanley L. Kameny.
  5. %% Revised 23 Mar 1993. Version 1.4.
  6. %% Added capability for using either the Taylor series package or the
  7. %% Truncated Power Series Package.
  8. %% Added provisions for transformation of certain irrational functions
  9. %% into rational functions before limit calculation in order to be able
  10. %% to compute series.
  11. %% Changed the algebraic interface so that if limit package fails, an
  12. %% equivalent of the original expression is returned.
  13. %% Allowed for limited recursion through limsimp.
  14. %% Corrected several bugs.
  15. %% Date: 10 Oct 1990. Original version.
  16. %% The Truncated Power Series package is used for non-critical points.
  17. %% L'Hopital's rule is used in critical cases, with preprocessing of
  18. %% <infinity - infinity> forms and reformatting of product forms in
  19. %% order to be able to apply l'Hopital's rule. A limited amount of
  20. %% bounded arithmetic is also employed where applicable.
  21. %% This limits package makes use of the ideas embodied in the
  22. %% limit.red package, by Ian Cohen and John Fitch, 11 July 1990
  23. %% that is in reduce-netlib; in fact, some code is lifted bodily.
  24. %% The idea of using the Truncated Power Series package to compute
  25. %% limits at non-critical points, and the substitutions used in limit!+
  26. %% and limit!- come from there.
  27. load!-package 'tps; %load!-package 'taylor;
  28. lisp(ps!:order!-limit := 100);
  29. switch usetaylor; off usetaylor;
  30. fluid '(!*precise lhop!# lplus!# !*protfg !*msg !*rounded !*complex
  31. !#nnn lim00!# !*crlimtest !*lim00rec);
  32. !*lim00rec := t; % Default value.
  33. global '(erfg!* exptconv!#);
  34. global '(abslims!#);
  35. symbolic(abslims!# := {0,1,-1,'infinity,'(minus infinity)});
  36. % others may be added.
  37. fluid '(lsimpdpth); global '(ld0!#); symbolic(ld0!# := 3);
  38. flag('(limit limit!+ limit!- limit2),'full);
  39. symbolic
  40. for each c in '(limit limit!+ limit!- limit2) do
  41. <<remflag({c},'opfn); put(c,'simpfn,'simplimit)>>;
  42. symbolic procedure limit2(top,bot,xxx,a);
  43. lhopital(top,bot,xxx,a) where lhop!#=0;
  44. symbolic procedure limit!+(ex,x,a);
  45. <<ex := simp!* limlogsort ex;
  46. if a = 'infinity then rederr "Cannot approach infinity from above"
  47. else if a = '(minus infinity) then
  48. limit(prepsq subsq(ex,list(x .
  49. list('quotient,-1,list('expt,'!*eps!*,2)))),'!*eps!*,0)
  50. else limit(prepsq subsq(ex,list(x .
  51. list('plus,a,list('expt,'!*eps!*,2)))),'!*eps!*,0)>>;
  52. symbolic procedure limit!-(ex,x,a);
  53. <<ex := simp!* limlogsort ex;
  54. if a = 'infinity then
  55. limit(prepsq subsq(ex,list(x .
  56. list('quotient,1,list('expt,'!*eps!*,2)))),'!*eps!*,0)
  57. else if a = '(minus infinity) then
  58. rederr "Cannot approach -infinity from below"
  59. else limit(prepsq subsq(ex,list(x .
  60. list('difference,a,list('expt,'!*eps!*,2)))),'!*eps!*,0)>>;
  61. symbolic procedure limit(ex,xxx,a); limit0(limlogsort ex,xxx,a)
  62. where !*combinelogs=nil,lhop!#=0,lplus!#=0,lim00!#=nil,lsimpdpth=0;
  63. symbolic procedure limlogsort x;
  64. begin scalar !*precise;
  65. x := prepsq simp!* x;
  66. return if countof('log,x)>1 then logsort x else x
  67. end;
  68. symbolic procedure countof(u,v);
  69. if u = v then 1 else if atom v then 0
  70. else countof(u,car v)+countof(u,cdr v);
  71. symbolic procedure simplimit u;
  72. % The kludgey handling of cot needs to be fixed some day.
  73. begin scalar fn,exprn,var,val,old,v,!*precise,!*protfg;
  74. if length u neq 4
  75. then rerror(limit,1,
  76. "Improper number of arguments to limit operator");
  77. fn:= car u; exprn := cadr u; var := !*a2k caddr u; val := cadddr u;
  78. !*protfg := t; % ACH: I'm not sure why this is needed.
  79. old := get('cot,'opmtch);
  80. put('cot,'opmtch,
  81. '(((!~x) (nil . t) (quotient (cos !~x) (sin !~x)) nil)));
  82. v := errorset!*({'apply,mkquote fn,mkquote {exprn,var,val}},nil);
  83. put('cot,'opmtch,old);
  84. !*protfg := nil;
  85. return if errorp v or (v := car v) = aeval 'failed then mksq(u,1)
  86. else simp!* v
  87. end;
  88. symbolic procedure limit0(exp,x,a);
  89. begin scalar exp1;
  90. exp1 := simp!* exp;
  91. if a = 'infinity then
  92. return limit00(subsq(exp1,{x . {'quotient,1,{'expt,x,2}}}),x);
  93. if a = '(minus infinity) then
  94. return limit00(subsq(exp1,{x . {'quotient,-1,{'expt,x,2}}}),x);
  95. return
  96. (<<!*protfg := t;
  97. y := errorset!*
  98. ({'subsq,mkquote(exp := simp!* exp),mkquote{(x . a)}},nil)
  99. where !*expandlogs=t;
  100. !*protfg := nil;
  101. if not (errorp y) and not ((y := car y) = aeval 'failed)
  102. then mk!*sq y
  103. else if neq(a,0) then limit00(subsq(exp1,{x .
  104. {'plus,a,x}}),x)
  105. else limit00(exp1,x)>> where y=nil) end;
  106. symbolic procedure limit00(ex,x);
  107. begin scalar p,p1,z,xpwrlcm,lim,ls;
  108. if (lim := crlimitset(p := prepsq ex,x)) then go to ret;
  109. if not lim00!# then
  110. <<lim00!# := not !*lim00rec;
  111. p1 := factrprep prepsq ex;
  112. if (xpwrlcm := xpwrlcmp(p1,x)) neq 1 then
  113. <<ex := subsq(ex,{x . {'expt,x,xpwrlcm}});
  114. p1 := factrprep prepsq ex>>;
  115. if (z := pwrdenp(p1,x)) neq 1 then
  116. ex := simp!*{'expt,p1,z};
  117. if (lim := crlimitset(p := prepsq ex,x)) then go to ret>>;
  118. % tps has failed because ex has a branch point at a or is undefined
  119. % at a or tps itself has failed or Reduce has not recognized the
  120. % numeric value of an expression.
  121. if %xpwrlcm and xpwrlcm>1 or
  122. lsimpdpth>ld0!#
  123. then lim := aeval 'failed else
  124. <<lsimpdpth := lsimpdpth + 1; ls := t;
  125. lim := limsimp(p,x);
  126. if prepsq simp!* lim = 'failed and lsimpdpth=1 then
  127. <<exptconv!# := nil; p := expt2exp(p,x);
  128. if exptconv!# then lim := limsimp(p,x)>> >>;
  129. ret: return
  130. <<if ls then lsimpdpth := lsimpdpth - 1;
  131. if not z or z = 1 or lim=0 then lim
  132. else if (ls := prepsq simp!* lim) = '(minus infinity)
  133. then if (-1)^z = 1 then aeval 'infinity else lim
  134. else if ls member '(infinity failed) then lim
  135. else mk!*sq simp!* {'expt,prepsq simp!* lim,{'quotient,1,z}}>>
  136. end;
  137. symbolic procedure factrprep p;
  138. begin scalar !*factor;
  139. !*factor := t;
  140. return prepsq simp!* p end;
  141. symbolic procedure expt2exp(p,x);
  142. if atom p then p
  143. else if eqcar(p,'expt)
  144. and not freeof(cadr p,x) and not freeof(caddr p,x) then
  145. <<exptconv!# := t; {'expt,'e,{'times,{'log,cadr p},caddr p}}>>
  146. else expt2exp(car p,x) . expt2exp(cdr p,x);
  147. symbolic procedure xpwrlcmp(p,x);
  148. if atom p then 1
  149. else if eqcar(p,'expt) and cadr p = x then getdenom caddr p
  150. else if eqcar(p,'sqrt) then getdenomx(cadr p,x)
  151. else lcm(xpwrlcmp(car p,x),xpwrlcmp(cdr p,x));
  152. symbolic procedure getdenomx(p,x);
  153. if freeof(p,x) then 1
  154. else if eqcar(p,'minus) then getdenomx(cadr p,x)
  155. else if p = x or eqcar(p,'times) and x member cdr p then 2
  156. else xpwrlcmp(p,x);
  157. symbolic procedure getdenom p;
  158. if eqcar(p,'minus) then getdenom cadr p
  159. else if eqcar(p,'quotient) and numberp caddr p then caddr p
  160. else 1;
  161. symbolic procedure pwrdenp(p,x);
  162. if atom p then 1
  163. else if eqcar(p,'expt) and not freeof(cadr p,x)
  164. then getdenom caddr p
  165. else if eqcar(p,'sqrt) and not freeof(cadr p,x) then 2
  166. else if eqcar(p,'minus) then pwrdenp(cadr p,x)
  167. else if car p member '(times quotient) then
  168. (<<for each c in cdr p do m := lcm(m,pwrdenp(c,x)); m>>
  169. where m=1)
  170. else if atom car p then 1
  171. else lcm(pwrdenp(car p,x),pwrdenp(cdr p,x));
  172. symbolic procedure limitset(ex,x,a);
  173. if !*usetaylor then
  174. <<!*protfg := t;
  175. ex := errorset!*({'limit1t,mkquote ex,mkquote x,mkquote a},nil);
  176. !*protfg := nil;
  177. if errorp ex then nil else car ex>>
  178. else % use tps.
  179. begin scalar oldpslim;
  180. !*protfg := t; oldpslim := simppsexplim '(1);
  181. ex := errorset!*({'limit1p,mkquote ex,mkquote x,mkquote a},nil);
  182. !*protfg := nil; simppsexplim list car oldpslim;
  183. return if errorp ex then nil else car ex
  184. end;
  185. symbolic procedure limit1t(ex,x,a);
  186. begin scalar nnn, vvv,oldklist;
  187. oldklist := get('taylor!*,'klist);
  188. ex := {ex,x,a,0};
  189. vvv := errorset!*({'simptaylor,mkquote ex},!*backtrace);
  190. put('taylor!*,'klist,oldklist);
  191. if errorp vvv then <<if !*backtrace then break();return nil>>
  192. else ex := car vvv;
  193. if kernp ex then ex := mvar numr ex
  194. else return nil;
  195. if not eqcar(ex,'taylor!*) then return nil
  196. else ex := cadr ex;
  197. % ex is now the list of coefs and values, but we need the lowest
  198. % order non-zero value, which may not be the first of these.
  199. % if this list is empty the result is zero
  200. while ex and null numr cdr car ex do ex := cdr ex;
  201. if null ex then return (!#nnn := 0) else
  202. !#nnn := nnn := caaaar ex;
  203. vvv := cdar ex;
  204. return
  205. if tayexp!-greaterp(nnn,0) then 0
  206. else if nnn=0 then mk!*sq vvv
  207. else if !*complex then 'infinity
  208. else if domainp(nnn := numr vvv) then
  209. (if !:minusp nnn
  210. then aeval '(minus infinity) else 'infinity)
  211. else aeval{'times,{'sign,prepsq vvv},'infinity}
  212. end;
  213. symbolic procedure limit1p(ex,x,a);
  214. begin scalar aaa, nnn, vvv;
  215. aaa := mk!*sq simpps1(ex,x,a);
  216. !#nnn := nnn := mk!*sq simppsorder list aaa;
  217. vvv := simppsterm1(aaa,min(nnn,0));
  218. return
  219. if nnn>0 then 0
  220. else if nnn=0 then mk!*sq vvv
  221. else if !*complex then 'infinity
  222. else if domainp(nnn := car vvv) then
  223. (if !:minusp nnn then aeval '(minus infinity)
  224. else 'infinity)
  225. else aeval{'times,{'sign,prepsq vvv},'infinity}
  226. end;
  227. symbolic procedure crlimitset(ex,x);
  228. (begin scalar lim1,lim2,n1,fg,limcr,!#nnn;
  229. lim1 := limitset(ex,x,0);
  230. if null lim1 then if r and c then return nil else go to a;
  231. if (n1 := !#nnn) < 0 or lim1 member abslims!#
  232. or r and c then return lim1;
  233. a: if not !*crlimtest then return lim1;
  234. if not r then on rounded; if not c then on complex;
  235. if not (lim2 := limitset(ex,x,0))
  236. or !#nnn > n1 then <<fg := t; go to ret>>;
  237. if !#nnn < n1 or lim2 member abslims!# then go to ret;
  238. % at this point, both lim1 and lim2 have values. If they are
  239. % equivalent, we want lim1; otherwise lim2.
  240. if (limcr := topevalsetsq lim1) and
  241. evalequal(prepsq simp!* lim2,prepsq limcr)
  242. then fg := t;
  243. ret:if not r then off rounded; if not c then off complex;
  244. return if fg then lim1 else lim2 end)
  245. where r=!*rounded,c=!*complex,!*msg=nil;
  246. symbolic procedure topevalsetsq u;
  247. <<!*protfg := t;
  248. if not r then on rounded; if not c then on complex;
  249. u := errorset!*({'simp!*,{'aeval,{'prepsq,{'simp!*,mkquote u}}}},
  250. nil);
  251. !*protfg := nil;
  252. if not r then off rounded;if not c then off complex;
  253. if errorp u then nil else car u>>
  254. where r=!*rounded,c=!*complex,!*msg=nil;
  255. put('times,'limsfn,'ltimesfn);
  256. put('quotient,'limsfn,'lquotfn);
  257. put('plus,'limsfn,'lplusfn);
  258. put('expt,'limsfn,'lexptfn);
  259. symbolic procedure limsimp(ex,x);
  260. % called when limit1 has failed, to apply more sophisticated methods.
  261. % output must be aeval form.
  262. begin scalar y,c,z,m,ex0;
  263. if eqcar(ex,'minus) then <<m := t; ex := cadr ex>>;
  264. ex0 := ex;
  265. if not atom ex then % check for plus, times, or quotient.
  266. <<if(z := get(y := car ex,'limsfn))
  267. then ex := apply(z,list(ex,x))>>
  268. else <<if ex eq x then ex := 0; go to ret>>;
  269. if y eq 'plus then go to ret;
  270. if y eq 'expt then if ex then return ex else ex := ex0 . 1;
  271. if z then<<z := car ex; c := cdr ex>>
  272. else <<z := prepsq !*f2q numr(ex := simp!* ex);
  273. c := prepsq !*f2q denr ex>>;
  274. ex := lhopital(z,c,x,0);
  275. ret: if m and prepsq simp!* ex neq 'failed then
  276. ex := aeval lminus2 ex;
  277. return ex end;
  278. symbolic procedure lminus2 ex;
  279. if numberp ex then -ex
  280. else if eqcar(ex,'minus) then cadr ex
  281. else list('minus,ex);
  282. symbolic procedure ltimesfn(ex,x); specchk(ex,1,x);
  283. symbolic procedure lquotfn(ex,x);
  284. % (if eqcar(n,'expt) and (nlim :=lexptfn(n,x))
  285. specchk(cadr ex,caddr ex,x);
  286. symbolic procedure lexptfn(ex,x);
  287. if not evalequal(cadr ex,0) and limit00(simp!* caddr ex,x)=0
  288. then 1;
  289. symbolic procedure specchk(top,bot,x);
  290. begin scalar tlist,blist,tinfs,binfs,tlogs,blogs,tzros,bzros,
  291. tnrms,bnrms,m;
  292. if eqcar(top,'minus) then <<m := t; top := cadr top>>;
  293. if eqcar(bot,'minus) then <<m := not m; bot := cadr bot>>;
  294. tlist := limsort(timsift(top,x),x);
  295. blist := limsort(timsift(bot,x),x);
  296. tinfs := cdr(tlogs := logcomb(cadr tlist,x)); tlogs := car tlogs;
  297. binfs := cdr(blogs := logcomb(cadr blist,x)); blogs := car blogs;
  298. tzros := car tlist; tnrms := caddr tlist;
  299. bzros := car blist; bnrms := caddr blist;
  300. if tlogs and not blogs then
  301. <<top := triml append(tlogs,tnrms);
  302. bot := triml append(bzros,append(binfs,
  303. append(bnrms,trimq append(tinfs,tzros))))>>
  304. else if blogs and not tlogs then
  305. <<bot := triml append(blogs,bnrms);
  306. top := triml append(tzros,append(tinfs,
  307. append(tnrms,trimq append(binfs,bzros))))>>
  308. else
  309. <<top := triml append(cadr tlist,trimq bzros);
  310. bot := triml append(cadr blist,
  311. append(bnrms,trimq append(tzros,tnrms)))>>;
  312. if m then top := list('minus,top);
  313. return top . bot end;
  314. symbolic procedure trimq l;
  315. if l then list list('quotient,1,
  316. if length l>1 then 'times . l else car l);
  317. symbolic procedure triml l;
  318. if null l then 1 else if length l>1 then 'times . l else car l;
  319. symbolic procedure limsort(ex,x);
  320. begin scalar zros,infs,nrms,q,s;
  321. for each c in ex do
  322. if (q := numr(s := simp!* limit00(simp!* c,x)))
  323. and numberp q and not zerop q then nrms := q . nrms
  324. else if null q or zerop q then zros := c . zros
  325. else if caaar q memq '(failed infinity) then infs := c.infs
  326. else nrms := (prepsq s) . nrms;
  327. return list(zros,infs,nrms) end;
  328. symbolic procedure logcomb(tinf,x);
  329. % separate product list into log terms and others.
  330. begin scalar tlog,c,z;
  331. while tinf do
  332. <<c := car tinf; tinf := cdr tinf;
  333. if eqcar(c,'log)
  334. or eqcar(c,'expt) and eqcar(cadr c,'log)
  335. or eqcar(c,'plus) and
  336. (eqcar(cadr(c := logjoin(c,x)),'log)
  337. or eqcar(cadr c,'minus) and eqcar(cadadr c,'log))
  338. and freeof(cddr c,x)
  339. then tlog := c . tlog else z := c . z>>;
  340. return tlog . reversip z end;
  341. symbolic procedure logjoin(p,x);
  342. % combine log terms in sum list into a single log.
  343. begin scalar ll,z;
  344. for each c in cdr p do
  345. if freeof(c,x) then z := c . z
  346. else if eqcar(c,'log) then ll := (cadr c) . ll
  347. else if eqcar(c,'minus) and eqcar(cadr c,'log) then
  348. ll := list('quotient,1,cadadr c) . ll
  349. else z := c . z;
  350. if ll then ll := list list('log,'times . ll);
  351. return (car p) . append(ll,reversip z) end;
  352. symbolic procedure timsift(ex,x);
  353. if eqcar(ex,'times) then cdr ex
  354. else if eqcar(ex,'plus) then list logjoin(ex,x)
  355. % for plus, combine log terms, change infinity - infinity to
  356. % inner quotient.
  357. else list ex;
  358. symbolic procedure lplusfn(ex,x);
  359. % combine logs and evaluate each limit term. if infinity - infinity
  360. % is found, attempt conversion to quotient form for lhopital.
  361. begin scalar z,infs,nrms,vals,vp,vm,cz,vnix;
  362. lplus!# := lplus!# + 1;
  363. % write "lplus#=",lplus!#; terpri();
  364. if lplus!#>4 then return aeval 'failed;
  365. z := limsort(cdr ex,x); % ignore car z, a list of 0's.
  366. nrms := caddr z; infs := cadr z;
  367. if length infs>1 then
  368. <<infs := logjoin('plus . infs,x);
  369. infs := if eqcar(infs,'plus) then cdr infs else list infs>>;
  370. % at this point, only infs needs to be evaluated.
  371. vals := for each c in infs collect
  372. minfix prepsq simp!* limit00(simp!* c,x);
  373. z := infs;
  374. for each c in vals do
  375. <<cz := car z; z := cdr z;
  376. if c eq 'infinity then vp := cz . vp
  377. else if c = '(minus infinity) then vm := cz . vm
  378. else if c eq 'failed then vnix := cz . vnix
  379. else nrms := cz . nrms>>;
  380. if vm and not vp or vp and not vm or length vnix = 1
  381. or length vm > 1 or length vp > 1 then return aeval 'failed;
  382. if vm then vm := qform(car vp,vm);
  383. if vnix then vnix := qform(car vnix,cdr vnix);
  384. vm := append(nrms,append(vm,vnix));
  385. return if null vm then 0 else
  386. limit00(simp!* if length vm>1 then 'plus . vm else car vm,x)
  387. end;
  388. symbolic procedure minfix v;
  389. if eqcar(v,'minus) and numberp cadr v then -cadr v else v;
  390. symbolic procedure qform(a,b);
  391. list list('quotient,list('plus,1,
  392. list('quotient,if length b = 1 then car b else 'plus . b,a)),
  393. list ('quotient,1,a));
  394. symbolic procedure lhopital(top,bot,xxx,a);
  395. begin scalar limt, limb, nvt, nvb;
  396. nvt := notval(limt := limfix(top,xxx,a));
  397. nvb := notval(limb := limfix(bot,xxx,a));
  398. % possibilities for lims are {failed, infinity, -infinity, bounded,
  399. % nonzero, zero} and each combination of cases has to be handled.
  400. if limt=0 and limb=0 or nvt and nvb then go to lhop;
  401. if specval limt or specval limb then return speccomb(limt,limb);
  402. if limb=0 then return aeval 'infinity; % maybe impossible.
  403. return aeval list('quotient,limt,limb);
  404. lhop: lhop!# := lhop!#+1;
  405. % write "lhop#=",lhop!#; terpri();
  406. if lhop!#>6 then return aeval 'failed;
  407. return limit0(prepsq quotsq(diffsq(simp!* top,xxx),
  408. diffsq(simp!* bot,xxx)),xxx,a) end;
  409. symbolic procedure notval lim;
  410. not lim or infinp prepsq simp!* lim;
  411. symbolic procedure infinp x; member(x,'(infinity (minus infinity)));
  412. symbolic procedure specval lim;
  413. notval lim or lim eq 'bounded;
  414. symbolic procedure speccomb(a,b);
  415. aeval
  416. (if not a or not b or b eq 'bounded then 'failed
  417. else if notval b then 0
  418. else if notval a then
  419. if numberp b then
  420. if b>=0 then a
  421. else if a eq 'infinity then '(minus infinity) else 'infinity
  422. else ((if c then
  423. <<c := prepsq c;
  424. if evalgreaterp(c,0) then cc := 1 else if evallessp(c,0)
  425. then cc := -1;
  426. if cc then c := if a eq 'infinity then 1 else -1;
  427. if cc then
  428. if c*cc = 1 then 'infinity else '(minus infinity)
  429. else {'times,{'sgn,b},a}>> else {'quotient,a,b})
  430. where c=topevalsetsq prepsq simp!* b,cc=nil)
  431. else 'failed);
  432. symbolic procedure limfix(ex,x,a);
  433. (if val then val
  434. else limitest(ex,x,a))
  435. where val=limitset(ex,x,a);
  436. symbolic procedure limitest(ex,x,a);
  437. if ex then if atom ex then if ex eq x then a else ex else
  438. begin scalar y,arg,val;
  439. if eqcar(ex,'expt) then
  440. if cadr ex eq 'e then ex := list('exp,caddr ex)
  441. else return exptest(cadr ex,caddr ex,x,a);
  442. if (y := get(car ex,'fixfn)) then
  443. <<arg := cadr ex; val := limitset(arg,x,a);
  444. return apply1(y,
  445. if val then val else limitest(arg,x,a))>>
  446. else if (y := get(car ex,'limcomb)) then
  447. return apply3(y,cdr ex,x,a) end;
  448. symbolic procedure exptest(b,n,x,a);
  449. if numberp n then
  450. if n<0 then limquot1(1,exptest(b,-n,x,a))
  451. else if n=0 then 1 else
  452. ((if 2*y=n then limlabs limitest(b,x,a) else limitest(b,x,a))
  453. where y=n/2)
  454. else if numberp b and b>1 then limitest(list('exp,n),x,a);
  455. symbolic procedure limlabs a;
  456. if null a then nil
  457. else if infinp a then 'infinity
  458. else if a eq 'bounded then 'bounded else
  459. begin scalar n,d; d := denr(n := simp!* a); n := numr n;
  460. return if null n then a else if not numberp n then nil
  461. else mk!*sq abs a ./ d end;
  462. symbolic procedure limplus(exl,x,a);
  463. if null exl then 0
  464. else limplus1(mkalg limfix(car exl,x,a),limplus(cdr exl,x,a));
  465. symbolic procedure limplus1(a,b);
  466. if null a or null b then nil
  467. else if infinp a
  468. then if infinp b
  469. then if a eq b then a else nil else a
  470. else if infinp b then b
  471. else if a eq 'bounded or b eq 'bounded then 'bounded
  472. else mk!*sq addsq(simp!* a,simp!* b);
  473. symbolic procedure limtimes(exl,x,a);
  474. if null exl then 1
  475. else ltimes1(mkalg limfix(car exl,x,a),limtimes(cdr exl,x,a));
  476. symbolic procedure mkalg x;
  477. minfix if eqcar(x,'!*sq) then prepsq simp!* x else x;
  478. symbolic procedure ltimes1(a,b);
  479. begin scalar c;
  480. return if null a or null b then nil
  481. else if infinp a then
  482. if infinp b then
  483. if a = b then 'infinity else '(minus infinity)
  484. else if b eq 'bounded or b=0 then nil
  485. else if (c := limposp b) eq 'failed then nil
  486. else if c then a else lminus1 a
  487. else if infinp b then
  488. if a eq 'bounded or a=0 then nil
  489. else if (c := limposp a) eq 'failed then nil
  490. else if c then b else lminus1 b
  491. else if a eq 'bounded or b eq 'bounded then 'bounded
  492. else mk!*sq multsq(simp!* a,simp!* b) end;
  493. symbolic procedure limposp a;
  494. (if n and not numberp n then 'failed else n and n>0)
  495. where n=numr simp!* a;
  496. symbolic procedure lminus(exl,x,a);
  497. lminus1 mkalg limfix(car exl,x,a);
  498. symbolic procedure lminus1 a; if a then
  499. if a eq 'infinity then '(minus infinity)
  500. else if a = '(minus infinity) then 'infinity
  501. else if a eq 'bounded then a
  502. else mk!*sq negsq simp!* a;
  503. symbolic procedure limquot(exl,x,a);
  504. limquot1(mkalg limfix(car exl,x,a),mkalg limfix(cadr exl,x,a));
  505. symbolic procedure limquot1(a,b);
  506. begin scalar c;
  507. return if null a or null b then nil
  508. else if infinp a then
  509. if infinp b then nil
  510. else if b eq 'bounded then nil
  511. else if b=0 then a
  512. else if (c := limposp b) eq 'failed then nil
  513. else if c then a else lminus1 a
  514. else if infinp b then 0
  515. else if a eq 'bounded then if b=0 then nil else 'bounded
  516. else if b=0 or b eq 'bounded then nil
  517. else mk!*sq quotsq(simp!* a,simp!* b) end;
  518. put('log,'fixfn,'fixlog);
  519. put('sin,'fixfn,'fixsin);
  520. put('cos,'fixfn,'fixsin);
  521. put('sqrt,'fixfn,'fixsqrt);
  522. put('cosh,'fixfn,'fixcosh);
  523. put('sinh,'fixfn,'fixsinh);
  524. put('exp,'fixfn,'fixexp);
  525. put('plus,'limcomb,'limplus);
  526. put('minus,'limcomb,'lminus);
  527. put('times,'limcomb,'limtimes);
  528. put('quotient,'limcomb,'limquot);
  529. symbolic procedure fixlog x;
  530. if zerop x then '(minus infinity) else if infinp x then 'infinity;
  531. symbolic procedure fixsqrt x;
  532. if zerop x then 0 else if infinp x then 'infinity;
  533. symbolic procedure fixsin x;
  534. if infinp x then 'bounded;
  535. symbolic procedure fixcosh x;
  536. if infinp x then 'infinity;
  537. symbolic procedure fixsinh x;
  538. if infinp x then x;
  539. symbolic procedure fixexp x;
  540. if x eq 'infinity then x else if x = '(minus infinity) then 0;
  541. endmodule;
  542. end;