sfbern.red 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. module sfbern; % Procedures for computing Bernoulli numbers.
  2. %
  3. % Author: Chris Cannam, Oct 1992.
  4. % Module for Euler numbers added by Kerry Gaskell, Sep 1993
  5. %
  6. % Note there is currently no Bernoulli polynomial function.
  7. % There was one in an older version but it won't convert directly.
  8. % This is Something To Be Done.
  9. fluid '(compute!-bernoulli);
  10. imports complex!*on!*switch, complex!*off!*switch,
  11. complex!*restore!*switch;
  12. exports nearest!-int!-to!-bf, bernoulli!*calc, multi!*bern,
  13. single!*bern, retrieve!*bern;
  14. algebraic operator bernoulli;
  15. symbolic operator bernoulli!*calc;
  16. algebraic (bernoullirules := {
  17. bernoulli(~n) => 1 when numberp n and n = 0,
  18. bernoulli(~n) => -1/2 when numberp n and n = 1,
  19. bernoulli(~n) => 0 when numberp n and impart n = 0
  20. and n = floor n and n/2 neq floor (n/2) and n > 0,
  21. bernoulli(~n) => bernoulli!*calc n when numberp n
  22. and impart n = 0 and n = floor n and n > 0
  23. })$
  24. algebraic (let bernoullirules);
  25. algebraic procedure bernoulli!*calc n;
  26. begin scalar precom, result, prepre;
  27. % Loading the SPECFAUX module will do two things. First it will
  28. % set compute!-bernoulli to true, so that there is no future attempt
  29. % to load it. Then it will set up a table of values in the variable
  30. % bernoulli!-alist, where the table is computed at compile time rather
  31. % than load or run-time. This will make compiling specfaux.red a fairly
  32. % slow process. It also has bad consequences for any attempt to run
  33. % this code interpreted.
  34. % Note: ACN find the "algebraic symbolic" stuff here pretty heavy
  35. % and confusing, but without it REDUCE sticks in calls to aeval (etc)
  36. % in places where that is not wanted. Maybe a future version of the
  37. % language will make mixed algebraic/symbolic mode code less delicate.
  38. if (lisp null compute!-bernoulli) then
  39. symbolic <<errorset!*('(load_package '(specfaux)), nil); nil>>;
  40. precom := complex!*off!*switch();
  41. if (prepre := precision(0)) < !!nfpd
  42. then precision (!!nfpd + 1);
  43. result := algebraic symbolic retrieve!*bern(n);
  44. precision prepre;
  45. complex!*restore!*switch(precom);
  46. return result;
  47. end;
  48. symbolic procedure retrieve!*bern n;
  49. begin scalar info, result;
  50. integer heldpre;
  51. info := assoc(n, bernoulli!-alist);
  52. if not info then result := bern!*calc (n, '(() () ()))
  53. else
  54. << info := cdr info;
  55. if !*rounded then
  56. if (heldpre := cadr info) and heldpre >= c!:prec!:() then
  57. result := mk!*sq !*f2q rd!:prep caddr info
  58. else if (result := car info) then
  59. result := mk!*sq !*f2q mkround
  60. divbf(i2bf!: caadr result,
  61. i2bf!: cdadr result)
  62. else result := bern!*calc(n, info)
  63. else if not (result := car info) then
  64. result := bern!*calc(n,info) >>;
  65. return result;
  66. end;
  67. symbolic procedure bern!*calc(n, info);
  68. begin scalar result;
  69. result := single!*bern(n/2);
  70. if !*rounded then
  71. info := list (car info, c!:prec!:(), result)
  72. else info := list (result, cadr info, caddr info);
  73. bernoulli!-alist := (n . info) . bernoulli!-alist;
  74. return result;
  75. end;
  76. %
  77. % Computation of Bernoulli numbers using the algorithms of
  78. % one Herbert S. Wilf, presented by Sandra Fillebrown in the
  79. % Journal of Algorithms 13 (1992)
  80. %
  81. % Chris Cannam, October 1992
  82. %
  83. %
  84. % Useful auxiliary fn.
  85. %
  86. symbolic procedure nearest!-int!-to!-bf(x);
  87. (conv!:bf2i rb)
  88. where rb = (if lessp!:(x,bfz!*)
  89. then difference!:(x,bfhalf!*)
  90. else plus!:(x,bfhalf!*));
  91. %
  92. % Procedure to compute B(2k) for k = 2 ... n
  93. %
  94. % Returns list of even bernoullis from B(4) to B(2n),
  95. % in reverse order; only works when compiled, owing
  96. % to reliance upon msd!:, which is a compiled inline
  97. % macro.
  98. %
  99. % If called with rounded mode off, it computes the
  100. % exact quotient; otherwise it will usually approximate
  101. % (to the correct precision) if it saves time to do so.
  102. %
  103. symbolic procedure multi!*bern(n);
  104. begin scalar results, primes, tprimes, r0, rk, rkm1, b2k,
  105. tpi, pie, tk, n2k;
  106. integer thisp, gn, prepre, prernd, p2k, k2, plim, d2k;
  107. results := nil;
  108. prernd := !*rounded;
  109. if not prernd then on rounded;
  110. prepre := precision 0;
  111. if new!*bfs then
  112. << gn := 2 * n * msd!: n;
  113. if gn < (log2of10*!!nfpd) then precision (!!nfpd + 2)
  114. else if prepre > (gn/3) or not prernd then
  115. precision (gn/3 + 1)
  116. else precision (prepre + 2) >>
  117. else
  118. << gn := 2 * n * length explode n;
  119. if gn < !!nfpd then precision (!!nfpd + 2)
  120. else if prepre > gn or not prernd then
  121. precision (gn + 2)
  122. else precision (prepre + 2) >>;
  123. tpi := pi!*(); pie := divbf(bfone!*, timbf(tpi, e!*()));
  124. if n < 1786 then primes := !*primelist!*
  125. else
  126. << primes := nil;
  127. for thisp := 3573 step 2 until (2*n + 1) do
  128. if primep thisp then primes := thisp . primes;
  129. primes := append(!*primelist!*, reverse primes) >>;
  130. r0 := sq2bf!* algebraic ((2*pi)**(-2));
  131. rkm1 := timbf(i2bf!: 4, r0);
  132. for k := 2:n do
  133. << k2 := 2*k;
  134. rk := timbf(i2bf!:(k2*(k2 - 1)), timbf(r0, rkm1));
  135. rkm1 := rk;
  136. tk := bfone!*; d2k := 1;
  137. plim := 1 + conv!:bf2i timbf(i2bf!: k2, pie);
  138. tprimes := cdr primes; thisp := car primes;
  139. while thisp <= plim do
  140. << p2k := thisp ** k2;
  141. tk := timbf(tk, divbf(i2bf!: p2k, i2bf!: (p2k - 1)));
  142. thisp := car tprimes;
  143. tprimes := cdr tprimes >>;
  144. tprimes := cdr primes; thisp := car primes;
  145. while thisp <= k+1 do
  146. << if cdr divide (k2, thisp - 1) = 0 then
  147. d2k := d2k * thisp;
  148. thisp := car tprimes;
  149. tprimes := cdr tprimes >>;
  150. if primep (k2 + 1) then d2k := d2k * (k2 + 1);
  151. n2k := timbf(timbf(rk, tk), i2bf!: d2k);
  152. if prernd then
  153. b2k := mk!*sq !*f2q mkround
  154. divbf (i2bf!: (((-1)**(k+1)) *
  155. nearest!-int!-to!-bf n2k),
  156. i2bf!: d2k)
  157. else b2k := list ('!*sq, (((-1)**(k+1)) *
  158. nearest!-int!-to!-bf n2k) . d2k, t);
  159. results := b2k . results >>;
  160. precision prepre;
  161. if not prernd then off rounded;
  162. return results;
  163. end;
  164. %
  165. % Procedure to compute B(2n). If it is called with rounded
  166. % mode off, it computes the exact quotient; otherwise it
  167. % will approximate (to the correct precision) whenever it
  168. % saves time to do so.
  169. %
  170. symbolic procedure single!*bern(n);
  171. begin scalar result, primes, tprimes, rn, tn, n2n, pie;
  172. integer d2n, thisp, gn, prepre, prernd, p2n, n2, plim;
  173. prernd := !*rounded;
  174. if not prernd then on rounded;
  175. prepre := precision 0;
  176. if new!*bfs then
  177. << gn := 2 * n * msd!: n;
  178. if gn < (log2of10*!!nfpd) then precision (!!nfpd + 2)
  179. else if prepre > (gn/3) or not prernd then
  180. precision (gn/3 + 1)
  181. else precision (prepre + 2) >>
  182. else
  183. << gn := 2 * n * length explode n;
  184. if gn < !!nfpd then precision (!!nfpd + 2)
  185. else if prepre > gn or not prernd then
  186. precision (gn + 1)
  187. else precision (prepre + 2) >>;
  188. pie := divbf(bfone!*, timbf(pi!*(), e!*()));
  189. if n < 1786 then primes := !*primelist!*
  190. else
  191. << primes := nil;
  192. for thisp := 3573 step 2 until (2*n + 1) do
  193. if primep thisp then primes := thisp . primes;
  194. primes := append(!*primelist!*, reverse primes) >>;
  195. n2 := 2*n;
  196. rn := divbf(i2bf!: (2 * factorial n2),
  197. sq2bf!* algebraic ((2*pi)**(n2)));
  198. tn := bfone!*; d2n := 1;
  199. plim := 1 + conv!:bf2i timbf(i2bf!: n2, pie);
  200. tprimes := cdr primes; thisp := car primes;
  201. while thisp <= plim do
  202. << p2n := thisp ** n2;
  203. tn := timbf(tn, divbf(i2bf!: p2n, i2bf!: (p2n - 1)));
  204. thisp := car tprimes;
  205. tprimes := cdr tprimes >>;
  206. tprimes := cdr primes; thisp := car primes;
  207. while thisp <= n+1 do
  208. << if cdr divide (n2, thisp - 1) = 0 then
  209. d2n := d2n * thisp;
  210. thisp := car tprimes;
  211. tprimes := cdr tprimes >>;
  212. if primep (n2 + 1) then d2n := d2n * (n2 + 1);
  213. n2n := timbf(timbf(rn, tn), i2bf!: d2n);
  214. precision prepre;
  215. if prernd then
  216. result := mkround divbf(i2bf!: (((-1)**(n+1)) *
  217. nearest!-int!-to!-bf n2n),
  218. i2bf!: d2n)
  219. else
  220. << off rounded;
  221. result := list ('!*sq, (((-1)**(n+1)) *
  222. nearest!-int!-to!-bf n2n) . d2n, t) >>;
  223. return result;
  224. end;
  225. % Euler numbers module by Kerry Gaskell
  226. algebraic operator Euler;
  227. algebraic
  228. let { Euler(0) => 1,
  229. Euler(~n) => Euler_aux(n) when fixp n and n > 0};
  230. flag('(euler_aux),'opfn);
  231. symbolic procedure Euler_aux(n);
  232. if not evenp n then 0 else
  233. begin scalar nn,list_of_bincoeff, newlist, old, curr,eulers,sum;
  234. list_of_bincoeff := { 1 };
  235. eulers :={ -1,1};
  236. nn := -2;
  237. while N > 0 do
  238. << nn := nn + 1;
  239. old := 0;
  240. newlist := {};
  241. while not(list_of_bincoeff = {}) do
  242. << curr := first list_of_bincoeff;
  243. newlist := (old + curr) . newlist;
  244. old := curr;
  245. list_of_bincoeff := rest list_of_bincoeff;
  246. >>;
  247. list_of_bincoeff := 1 . newlist;
  248. n := n -1 ;
  249. % now that we have got the row of Pascal's triangle
  250. % we can use it and compute the Next Euler number.
  251. if nn > 0 and evenp nn then <<
  252. curr := list_of_bincoeff;
  253. old := eulers; sum := 0;
  254. while old do <<
  255. curr := cddr curr;
  256. sum := sum - first old * first curr;
  257. old := cdr old;
  258. >>;
  259. eulers := sum . eulers;
  260. >>;
  261. >>;
  262. return first eulers;
  263. end;
  264. endmodule;
  265. end;