\ sph_bes_neu.4th \ \ Spherical Bessel and Neumann functions for large index range \ \ Use recurrence relations to compute the spherical Bessel and \ Neumann functions, j_l(x) and n_l(x), for l over the range \ 0 to 999. The relative accuracy of j_l(x) and n_l(x) is \ better than 5e-16 for x <= 100, for l=0 to 100 -- see test \ code below. \ \ The computed function values for different l's are stored in \ arrays rbes{ and rneu{ with l as the index. \ \ The recursive algorithm implemented here is the one from Ref. 1. \ The computed functions have standard normalization, e.g. \ \ j_0(x) = sin(x)/x \ j_1(x) = sin(x)/x^2 - cos(x)/x \ j_2(x) = (3/x^3 - 1/x)*sin(x) - (3/x^2)*cos(x) \ ... \ n_0(x) = -cos(x)/x \ n_1(x) = -cos(x)/x^2 - sin(x)/x \ n_2(x) = -(3/x^3 - 1/x)*cos(x) -(3/x^2)*sin(x) \ \ Forth version by Krishna Myneni, 2022-07-02 \ \ References \ 1. E. Gillman and H. R. Fiebig, "Accurate recursive generation \ of spherical Bessel and Neumann functions for a large range \ of indices," Computers in Physics vol. 2, p. 62 (1988). \ \ Notes: \ 1. The floating point words FSIN and FCOS are used separately \ to obtain the sin and cos of the arguments, instead of \ FSINCOS. In kForth, FSIN and FCOS use the C math library, \ which, under Linux, provides much higher accuracy for large \ arguments than using the word FSINCOS which calls the f.p.u. \ instruction of the same name. \ \ 2. Reference values for test code are computed using the \ functions, SphericalBesselJ[l,x] and SphericalBesselY[l,x] \ on Wolfram Alpha. [UNDEFINED] square [IF] : square dup * ; [THEN] BEGIN-MODULE BASE @ DECIMAL fvariable cx fvariable sx fvariable cu fvariable cv 0 value lu 0 value lv 0 value w Public: 1000 value MAX-L MAX-L FLOAT ARRAY rbes{ MAX-L FLOAT ARRAY rneu{ : sphfuncs ( F: x -- ) \ Set starting values j_lmax-1(x) and n_0(x) for recursion 1.0e0 fdup rbes{ MAX-L 1- } f! rbes{ MAX-L 2- } f! fdup fsin sx f! fdup fcos fdup cx f! rneu{ 0 } f! fdup sx f@ f* cx f@ f+ rneu{ 1 } f! fdup fsquare \ F: x x^2 \ Recursively generate j_l(x) and n_l(x) MAX-L 2 DO MAX-L I - to lu I 2- to lv fdup lv 1+ square 4 * 1- s>f f/ rneu{ lv } f@ f* fnegate rneu{ lv 1+ } f@ f+ rneu{ lv 2+ } f! fdup lu 1+ square 4 * 1- s>f f/ rbes{ lu 1+ } f@ f* fnegate rbes{ lu } f@ f+ rbes{ lu 1- } f! LOOP \ F: x x^2 \ Scale j_l(x) 3.0e0 f/ rbes{ 1 } f@ f* cx f@ f* fnegate rbes{ 0 } f@ rneu{ 1 } f@ f* f+ MAX-L 0 DO rbes{ I } f@ fover f/ rbes{ I } f! LOOP fdrop \ F: x \ Normalize j_l(x) and n_l(x) 1.0e0 fover f/ cu f! -1.0e0 cv f! \ F: x MAX-L 0 DO I 2* to w fdup w 1+ s>f f/ cu f@ f* fdup cu f! rbes{ I } f@ f* rbes{ I } f! w 1- s>f fover f/ cv f@ f* fdup cv f! rneu{ I } f@ f* fnegate rneu{ I } f! LOOP fdrop ; BASE ! END-MODULE TEST-CODE? [IF] [UNDEFINED] T{ [IF] include ttester.4th [THEN] BASE @ DECIMAL 1e-16 abs-near f! 5e-16 rel-near f! set-near TESTING SPHFUNCS t{ 0.1e0 sphfuncs -> }t t{ rbes{ 0 } f@ -> 9.98334166468281523E-001 r}t \ j_0 (0.1) t{ rbes{ 10 } f@ -> 7.27151099671367155E-021 r}t \ j_10 (0.1) t{ rbes{ 100 } f@ -> 7.46290351349733307E-290 r}t \ j_100(0.1) t{ rneu{ 0 } f@ -> -9.95004165278025766E+000 r}t \ n_0 (0.1) t{ rneu{ 10 } f@ -> -6.54901397465628083E+019 r}t \ n_10 (0.1) t{ rneu{ 100 } f@ -> -6.66647616739126082E+287 r}t \ n_100(0.1) t{ 1.0e0 sphfuncs -> }t t{ rbes{ 0 } f@ -> 8.41470984807896507E-001 r}t \ j_0 (1) t{ rbes{ 10 } f@ -> 7.11655264004731302E-011 r}t \ j_10 (1) t{ rbes{ 100 } f@ -> 7.44472774166107689E-190 r}t \ j_100(1) t{ rneu{ 0 } f@ -> -5.40302305868139717E-001 r}t \ n_0 (1) t{ rneu{ 10 } f@ -> -6.72215008256208444E+008 r}t \ n_10 (1) t{ rneu{ 100 } f@ -> -6.68307946325867751E+186 r}t \ n_100(1) t{ 10.0e0 sphfuncs -> }t t{ rbes{ 0 } f@ -> -5.44021110889369813E-002 r}t \ j_0 (10) t{ rbes{ 10 } f@ -> 6.46051544925642643E-002 r}t \ j_10 (10) t{ rbes{ 100 } f@ -> 5.83204018200587675E-090 r}t \ j_100(10) t{ rneu{ 0 } f@ -> 8.39071529076452452E-002 r}t \ n_0 (10) t{ rneu{ 10 } f@ -> -1.72453672088057849E-001 r}t \ n_10 (10) t{ rneu{ 100 } f@ -> -8.57322630932998279E+085 r}t \ n_100(10) t{ 100.0e0 sphfuncs -> }t t{ rbes{ 0 } f@ -> -5.06365641109758794E-003 r}t \ j_0 (100) t{ rbes{ 10 } f@ -> -1.95657859713429006E-004 r}t \ j_10 (100) t{ rbes{ 100 } f@ -> 1.08804770114383365E-002 r}t \ j_100(100) t{ rneu{ 0 } f@ -> -8.62318872287683934E-003 r}t \ n_0 (100) t{ rneu{ 10 } f@ -> 1.00257773736361539E-002 r}t \ n_10 (100) t{ rneu{ 100 } f@ -> -2.29838504915622810E-002 r}t \ n_100(100) t{ 200.0e0 sphfuncs -> }t t{ rbes{ 0 } f@ -> -4.36648648606997291E-003 r}t \ j_0 (200) t{ rbes{ 10 } f@ -> 3.54317289031424494E-003 r}t \ j_10 (200) t{ rbes{ 100 } f@ -> -1.93609723624755680E-003 r}t \ j_100(200) t{ rbes{ 200 } f@ -> 6.24553158028404332E-003 r}t \ j_200(200) t{ rbes{ 300 } f@ -> 7.62022360196212765E-032 r}t \ j_300(200) t{ rneu{ 0 } f@ -> -2.43593837503502955E-003 r}t \ n_0 (200) t{ rneu{ 10 } f@ -> 3.53275680310172060E-003 r}t \ n_10 (200) t{ rneu{ 100 } f@ -> -5.01666824197730591E-003 r}t \ n_100(200) t{ rneu{ 200 } f@ -> -1.26612996092208560E-002 r}t \ n_200(200) t{ rneu{ 300 } f@ -> -1.46283071227275816E+026 r}t \ n_300(200) BASE ! [THEN]