bessel.scm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; Bessel functions of integer order.
  21. ;;; This file may be compiled with the Scheme compiler.
  22. ;;; It does not depend upon any other code to work.
  23. (declare (usual-integrations))
  24. #|
  25. ;;; The following three are redundant with nscmutils/kernel/udefs
  26. (define pi/4 (atan 1 1))
  27. (define pi/2 (* 2 pi/4))
  28. (define pi (* 4 pi/4))
  29. |#
  30. (define 2/pi (/ 1 2 pi/4))
  31. (define 3pi/4 (* 3 pi/4))
  32. ;;; Utilities for special functions
  33. (define (round-to-even x)
  34. (let ((xn (inexact->exact (round x))))
  35. (if (odd? xn)
  36. (fix:+ xn 1)
  37. xn)))
  38. (define (poly-by-coeffs->value x . coeffs)
  39. (let lp ((coeffs coeffs))
  40. (if (null? (cdr coeffs))
  41. (car coeffs)
  42. (+ (car coeffs)
  43. (* x
  44. (lp (cdr coeffs)))))))
  45. ;;; From John F. Hart, et.al., Computer Approximations, QA297.C64 1968
  46. ;;; These are all good to at least 15 digits.
  47. (define (bessj0 x)
  48. (let ((ax (magnitude x)))
  49. (if (< ax 8.0)
  50. (let ((y (* x x))) ;Jzero 5845
  51. (/ (poly-by-coeffs->value y
  52. +.1859623176218978035283999449e+18
  53. -.4414582939181598183458448718e+17
  54. +.2334489171877869744571586698e+16
  55. -.4776555944267358775465713161e+14
  56. +.4621722250317180263694186830e+12
  57. -.2271490439553603267422190396e+10
  58. +.5513584564770752154116759317e+7
  59. -.5292617130384557364907747176e+4)
  60. (poly-by-coeffs->value y
  61. +.1859623176218977331294574009e+18
  62. +.2344750013658996756881142774e+16
  63. +.1501546244976975197238575580e+14
  64. +.6439867453513325627846468877e+11
  65. +.2042514835213435736159365899e+9
  66. +.4940307949181397241772754336e+6
  67. +.8847203675617550401186701293e+3
  68. +.1e+1)))
  69. (let* ((z (/ 8.0 ax))
  70. (y (* z z))
  71. (xx (- ax pi/4))
  72. (p0 ;Pzero 6546
  73. (/ (poly-by-coeffs->value y
  74. +.8554822541506661710252074e+4
  75. +.8894437532960619440762804e+4
  76. +.2204501043965180428995069e+4
  77. +.1286775857487141932988510e+3
  78. +.9004793474802880316384000e+0)
  79. (poly-by-coeffs->value y
  80. +.8554822541506662842462151e+4
  81. +.8903836141709595355210343e+4
  82. +.2214048851914710419825683e+4
  83. +.1308849004999238828351090e+3
  84. +.1e+1)))
  85. (q0 ;Qzero 6946
  86. (/ (poly-by-coeffs->value y
  87. -.37510534954957111594836e+2
  88. -.46093826814625174976377e+2
  89. -.13990976865960680088016e+2
  90. -.10497327982345548331260e+1
  91. -.93525953294031893049e-2)
  92. (poly-by-coeffs->value y
  93. +.2400674237117267479318819e+4
  94. +.2971983745208491990065486e+4
  95. +.921566975526530895082307e+3
  96. +.74428389741411178824152e+2
  97. +.1e1))))
  98. (* (sqrt (/ 2/pi ax))
  99. (- (* (cos xx) p0)
  100. (* z (sin xx) q0)))))))
  101. (define (bessj1 x)
  102. (let ((ax (magnitude x)))
  103. (if (< ax 8.0) ;Jone 6045
  104. (let ((y (* x x)))
  105. (/ (* x
  106. (poly-by-coeffs->value y
  107. +.695364226329838502166085207e+8
  108. -.8356785487348914291918495672e+7
  109. +.3209027468853947029888682298e+6
  110. -.58787877666568200462723094e+4
  111. +.6121876997356943874446879769e+2
  112. -.3983107983952332023421699105e+0
  113. +.1705769264349617107854016566e-2
  114. -.4910599276555129440130592573e-5
  115. +.9382193365140744507653268479e-8
  116. -.1107352224453730633782671362e-10
  117. +.63194310317443161294700346e-14))
  118. (poly-by-coeffs->value y
  119. +.139072845265967685120764336e+9
  120. +.6705346835482299302199750802e+6
  121. +.1284593453966301898121332163e+4
  122. +.1e+1)))
  123. (let* ((z (/ 8.0 ax))
  124. (y (* z z))
  125. (xx (- ax 3pi/4))
  126. (p1 ;Pone 6747
  127. (/ (poly-by-coeffs->value y
  128. +.1290918471896188077350689e+5
  129. +.1309042051103506486292571e+5
  130. +.313275295635506951011069e+4
  131. +.17431379748379024599685e+3
  132. +.122850537643590432633e+1)
  133. (poly-by-coeffs->value y
  134. +.1290918471896187879332737e+5
  135. +.1306678308784402036110575e+5
  136. +.310928141677002883350924e+4
  137. +.16904721775008609992033e+3
  138. +.1e+1)))
  139. (q1 ;Qone 7147
  140. (/ (poly-by-coeffs->value y
  141. ;+.14465282874995208675225e+3 ;This line or the next is in error
  142. +.14465282874995208765225e+3
  143. +.1744291689092425885102e+3
  144. +.5173653281836591636536e+2
  145. +.379944537969806734901e+1
  146. +.36363466476034710809e-1)
  147. (poly-by-coeffs->value y
  148. +.308592701333231723110639e+4
  149. +.373434010601630179517765e+4
  150. +.11191098527047487025919e+4
  151. +.8522392064341340397334e+2
  152. +.1e+1)))
  153. (ans
  154. (* (sqrt (/ 2/pi ax))
  155. (- (* (cos xx) p1)
  156. (* z (sin xx) q1)))))
  157. (if (< x 0.0)
  158. (- ans)
  159. ans)))))
  160. ;;; Although this is implemented with the usual recurrences, it is
  161. ;;; very subtle.
  162. (define (bessj n x)
  163. (let ((acc 40) (bigno 1.0e10) (bigni 1.0e-10))
  164. (cond ((fix:= n 0) (bessj0 x))
  165. ((fix:= n 1) (bessj1 x))
  166. ((= x 0.0) 0.0)
  167. ((< x 0.0)
  168. (if (even? n) (bessj n (- x)) (- (bessj n (- x)))))
  169. ((fix:< n 0)
  170. (if (even? n) (bessj (- n) x) (- (bessj (- n) x))))
  171. (else
  172. (let* ((ax (magnitude x)) (tox (/ 2.0 ax)))
  173. (if (> ax n)
  174. (let lp ((j 1) (bjm (bessj0 ax)) (bj (bessj1 ax)))
  175. (if (fix:= j n)
  176. (if (and (< x 0.0) (odd? n)) (- bj) bj)
  177. (lp (fix:+ j 1)
  178. bj
  179. (- (* j tox bj) bjm))))
  180. (let ((m (round-to-even (+ n (sqrt (* acc n)))))
  181. (bj 1.0) (bjp 0.0) (ans 0.0) (sum 0.0))
  182. (let lp ((j m))
  183. (if (fix:= j 0)
  184. (let ((ans (/ ans (- (* 2.0 sum) bj))))
  185. (if (and (< x 0.0) (odd? n)) (- ans) ans))
  186. (let ((bjm (- (* j tox bj) bjp)))
  187. (set! bjp bj)
  188. (set! bj bjm)
  189. (if (> (magnitude bj) bigno)
  190. (begin (set! bj (* bj bigni))
  191. (set! bjp (* bjp bigni))
  192. (set! ans (* ans bigni))
  193. (set! sum (* sum bigni))))
  194. (if (odd? j)
  195. (set! sum (+ sum bj)))
  196. (if (fix:= j n)
  197. (set! ans bjp))
  198. (lp (fix:- j 1))))))))))))
  199. #|
  200. ;;; Assymptotic formulae, for testing:
  201. (define (fact n)
  202. (if (< n 2)
  203. 1
  204. (* n (fact (- n 1)))))
  205. (define (bessj:0<x<<n n x)
  206. (/ (expt (/ x 2) n) (fact n)))
  207. (define (bessj:n<<x n x)
  208. (* (sqrt (/ 2 pi x))
  209. (cos (- x (* pi/2 n) pi/4))))
  210. |#
  211. (define (bessy0 x)
  212. (let ((ax (magnitude x)))
  213. (if (< ax 8.0)
  214. (let* ((y (* x x)) ;Yzero 6243
  215. (r0
  216. (poly-by-coeffs->value y
  217. -.122848349966864707119444888e+8 ;p00
  218. +.2950673961329634647867906439e+8 ;p01
  219. -.2540763578168434015208700066e+7 ;p02
  220. +.7768806299511773765193176993e+5 ;p03
  221. -.1193299661108745921129349868e+4 ;p04
  222. +.10753556131901778914962135e+2 ;p05
  223. -.6186687126256085875960782886e-1 ;p06
  224. +.2379830688791742855598085169e-3 ;p07
  225. -.6227852796374134180786140767e-6 ;p08
  226. +.1091804574277522610752537393e-8 ;p09
  227. -.119120749069566983004259626e-11 ;p10
  228. +.6321369945552678896098605e-15 ;p11
  229. ))
  230. (s0
  231. (poly-by-coeffs->value y
  232. +.1664514914558198835968659363e+9 ;q00
  233. +.75939734950276133884153062e+6 ;q01
  234. +.137072109013171838997378226e+4 ;q02
  235. +1.0 ;q03
  236. )))
  237. (+ (/ r0 s0)
  238. (* 2/pi (bessj0 x) (log x))))
  239. (let* ((z (/ 8.0 ax))
  240. (y (* z z))
  241. (xx (- ax pi/4))
  242. (p0 ;Pzero 6546
  243. (/ (poly-by-coeffs->value y
  244. +.8554822541506661710252074e+4
  245. +.8894437532960619440762804e+4
  246. +.2204501043965180428995069e+4
  247. +.1286775857487141932988510e+3
  248. +.9004793474802880316384000e+0)
  249. (poly-by-coeffs->value y
  250. +.8554822541506662842462151e+4
  251. +.8903836141709595355210343e+4
  252. +.2214048851914710419825683e+4
  253. +.1308849004999238828351090e+3
  254. +.1e+1)))
  255. (q0 ;Qzero 6946
  256. (/ (poly-by-coeffs->value y
  257. -.37510534954957111594836e+2
  258. -.46093826814625174976377e+2
  259. -.13990976865960680088016e+2
  260. -.10497327982345548331260e+1
  261. -.93525953294031893049e-2)
  262. (poly-by-coeffs->value y
  263. +.2400674237117267479318819e+4
  264. +.2971983745208491990065486e+4
  265. +.921566975526530895082307e+3
  266. +.74428389741411178824152e+2
  267. +.1e1))))
  268. (* (sqrt (/ 2/pi ax))
  269. (+ (* (sin xx) p0)
  270. (* z (cos xx) q0)))))))
  271. (define (bessy1 x)
  272. (let ((ax (magnitude x)))
  273. (if (< ax 8.0)
  274. (let* ((y (* x x)) ;Yone 6442
  275. (r0
  276. (poly-by-coeffs->value y
  277. -.2493247725431151099221863985e+8 ;p00
  278. +.678814979608784027013965029e+7 ;p01
  279. -.3418758685257648961162234201e+6 ;p02
  280. +.731876663732252704384675659e+4 ;p03
  281. -.8477929772037826827977473917e+2 ;p04
  282. +.5973109455969101918912869725e+0 ;p05
  283. -.2723714918114737334647812804e-2 ;p06
  284. +.8253358475754237969740284405e-5 ;p07
  285. -.1645797675540583390670878295e-7 ;p08
  286. +.2013974632712911344982964612e-10 ;p09
  287. -.118503924369772697029706524e-13 ;p10
  288. ))
  289. (s0
  290. (poly-by-coeffs->value y
  291. +.1271694748306711445338693265e+9 ;q00
  292. +.6291245810783959009675422035e+6 ;q01
  293. +.1241151964683171602676430057e+4 ;q02
  294. +1.0 ;q03
  295. )))
  296. (+ (/ (* x r0) s0)
  297. (* 2/pi
  298. (- (* (bessj1 x) (log x))
  299. (/ 1.0 x)))))
  300. (let* ((z (/ 8.0 ax))
  301. (y (* z z))
  302. (xx (- ax 3pi/4))
  303. (p1 ;Pone 6747
  304. (/ (poly-by-coeffs->value y
  305. +.1290918471896188077350689e+5
  306. +.1309042051103506486292571e+5
  307. +.313275295635506951011069e+4
  308. +.17431379748379024599685e+3
  309. +.122850537643590432633e+1)
  310. (poly-by-coeffs->value y
  311. +.1290918471896187879332737e+5
  312. +.1306678308784402036110575e+5
  313. +.310928141677002883350924e+4
  314. +.16904721775008609992033e+3
  315. +.1e+1)))
  316. (q1 ;Qone 7147
  317. (/ (poly-by-coeffs->value y
  318. +.14465282874995208675225e+3
  319. +.1744291689092425885102e+3
  320. +.5173653281836591636536e+2
  321. +.379944537969806734901e+1
  322. +.36363466476034710809e-1)
  323. (poly-by-coeffs->value y
  324. +.308592701333231723110639e+4
  325. +.373434010601630179517765e+4
  326. +.11191098527047487025919e+4
  327. +.8522392064341340397334e+2
  328. +.1e+1))))
  329. (* (sqrt (/ 2/pi ax))
  330. (+ (* (sin xx) p1)
  331. (* z (cos xx) q1)))))))
  332. #|
  333. ;;; These coefficients are from Numerical Recipes... not so good... 7digits.
  334. (define (bessy0 x)
  335. (let ((ax (magnitude x)))
  336. (if (< ax 8.0)
  337. (let* ((y (* x x))
  338. (r0
  339. (poly-by-coeffs->value y
  340. -2957821389.0
  341. +7062834065.0
  342. -512359803.6
  343. +10879881.29
  344. -86327.92757
  345. +228.4622733))
  346. (s0
  347. (poly-by-coeffs->value y
  348. +40076544269.0
  349. +745249964.8
  350. +7189466.438
  351. +47447.26470
  352. +226.1030244
  353. +1.0)))
  354. (+ (/ r0 s0)
  355. (* 2/pi (bessj0 x) (log x))))
  356. (let* ((z (/ 8.0 ax))
  357. (y (* z z))
  358. (xx (- ax pi/4))
  359. (p0
  360. (poly-by-coeffs->value y
  361. +1.0
  362. -0.1098628627e-2
  363. +0.2734510407e-4
  364. -0.2073370639e-5
  365. +0.2093887211e-6))
  366. (q0
  367. (poly-by-coeffs->value y
  368. -0.1562499995e-1
  369. +0.1430488765e-3
  370. -0.6911147651e-5
  371. +0.7621095161e-6
  372. -0.934945152e-7)))
  373. (* (sqrt (/ 2/pi ax))
  374. (+ (* (sin xx) p0)
  375. (* z (cos xx) q0)))))))
  376. (define (bessy1 x)
  377. (let ((ax (magnitude x)))
  378. (if (< ax 8.0)
  379. (let* ((y (* x x))
  380. (r0
  381. (poly-by-coeffs->value y
  382. -0.4900604943e13
  383. +0.1275274390e13
  384. -0.5153438139e11
  385. +0.7349264551e9
  386. -0.4237922726e7
  387. +0.8511937935e4))
  388. (s0
  389. (poly-by-coeffs->value y
  390. +0.2499580570e14
  391. +0.4244419664e12
  392. +0.3733650367e10
  393. +0.2245904002e8
  394. +0.1020426050e6
  395. +0.3549632885e3
  396. +1.0)))
  397. (+ (/ (* x r0) s0)
  398. (* 2/pi
  399. (- (* (bessj1 x) (log x))
  400. (/ 1.0 x)))))
  401. (let* ((z (/ 8.0 ax))
  402. (y (* z z))
  403. (xx (- ax 3pi/4))
  404. (p0
  405. (poly-by-coeffs->value y
  406. +1.0
  407. +0.183105e-2
  408. -0.3516396496e-4
  409. +0.2457520174e-5
  410. -0.240337019e-6))
  411. (q0
  412. (poly-by-coeffs->value y
  413. +0.04687499995
  414. -0.2002690873e-3
  415. +0.8449199096e-5
  416. -0.88228987e-6
  417. +0.105787412e-6)))
  418. (* (sqrt (/ 2/pi ax))
  419. (+ (* (sin xx) p0)
  420. (* z (cos xx) q0)))))))
  421. |#
  422. (define (bessy n x)
  423. (cond ((fix:= n 0) (bessy0 x))
  424. ((fix:= n 1) (bessy1 x))
  425. ((not (> x 0))
  426. (error "Argument out of range -- Bessel Y" n x))
  427. ((fix:< n 0)
  428. (if (even? n) (bessy (- n) x) (- (bessy (- n) x))))
  429. (else
  430. (let lp ((i 1) (yn (bessy1 x)) (yn-1 (bessy0 x)))
  431. (if (fix:= i n)
  432. yn
  433. (lp (fix:+ i 1)
  434. (- (/ (* 2 i yn) x) yn-1)
  435. yn))))))
  436. (define (bessh n x)
  437. (+ (bessj n x) (* +i (bessy n x))))
  438. #|
  439. (define (bessh:n<<x n x)
  440. (* (sqrt (/ 2 pi z))
  441. (exp (* +i (- z (* pi/2 n) pi/4)))))
  442. |#
  443. #|
  444. ;;; Consistency check based on Wronskian:
  445. ;;; J_{n+1}(x) Y_n(x) - J_n(x) Y_{n+1}(x) = 2/(pi x)
  446. (define (bessel-check n x)
  447. (/ (- (* (bessj (+ n 1) x) (bessy n x))
  448. (* (bessj n x) (bessy (+ n 1) x))
  449. (/ 2 (* pi x)))
  450. (/ 2 (* pi x))))
  451. (let lp ((x .0001) (worstx 0.0) (relerr 0.0))
  452. (if (> x 20)
  453. (list `(worst-x ,worstx relative-error ,relerr))
  454. (let ((err (bessel-check 0 x)))
  455. (if (> (magnitude err) (magnitude relerr))
  456. (lp (+ x .0001) x err)
  457. (lp (+ x .0001) worstx relerr)))))
  458. ;Value: ((worst-x 7.950999999994808 relative-error -1.1214144656680372e-13))
  459. ;;; Interestingly, there appears to be a problem just below 8.0, because
  460. ;;; except near here the errors are close to roundoff noise.
  461. (define win
  462. (frame 7.90 8.00 -2e-13 2e-13))
  463. (plot-function win
  464. (lambda (x)
  465. (bessel-check 0 x))
  466. 7.90
  467. 8.0
  468. 0.000001)
  469. (graphics-clear win)
  470. (graphics-close win)
  471. (define win
  472. (frame 0.0 20.0 -2e-13 2e-13))
  473. (plot-function win
  474. (lambda (x)
  475. (bessel-check 0 x))
  476. 0.1
  477. 20.0
  478. 0.0001)
  479. ;;; Graph is stored in bessel-error.jpg
  480. (define (foo z) ;Approx to J0 9.1.18 A&S
  481. (/ (integrate-closed-closed
  482. (lambda (theta)
  483. (cos (* z (sin theta))))
  484. 0.0
  485. pi
  486. 1e-16)
  487. pi))
  488. (define win
  489. (frame 0.0 20.0 -2e-15 2e-15))
  490. |#