1 /* specfunc/bessel_zero.c
3 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 /* Author: G. Jungman */
23 #include <gsl/gsl_math.h>
24 #include <gsl/gsl_errno.h>
25 #include <gsl/gsl_sf_airy.h>
26 #include <gsl/gsl_sf_pow_int.h>
27 #include <gsl/gsl_sf_bessel.h>
31 #include "bessel_olver.h"
33 /* For Chebyshev expansions of the roots as functions of nu,
34 * see [G. Nemeth, Mathematical Approximation of Special Functions].
35 * This gives the fits for all nu and s <= 10.
36 * I made the fits for other values of s myself [GJ].
39 /* Chebyshev expansion: j_{nu,1} = c_k T_k*(nu/2), nu <= 2 */
40 static const double coef_jnu1_a[] = {
68 /* Chebyshev expansion: j_{nu,1} = nu c_k T_k*((2/nu)^(2/3)), nu >= 2 */
69 static const double coef_jnu1_b[] = {
88 /* Chebyshev expansion: j_{nu,2} = c_k T_k*(nu/2), nu <= 2 */
89 static const double coef_jnu2_a[] = {
112 /* Chebyshev expansion: j_{nu,2} = nu c_k T_k*((2/nu)^(2/3)), nu >= 2 */
113 static const double coef_jnu2_b[] = {
136 /* Chebyshev expansion: j_{nu,3} = c_k T_k*(nu/3), nu <= 3 */
137 static const double coef_jnu3_a[] = {
160 /* Chebyshev expansion: j_{nu,3} = nu c_k T_k*((3/nu)^(2/3)), nu >= 3 */
161 static const double coef_jnu3_b[] = {
184 /* Chebyshev expansion: j_{nu,4} = c_k T_k*(nu/4), nu <= 4 */
185 static const double coef_jnu4_a[] = {
208 /* Chebyshev expansion: j_{nu,4} = nu c_k T_k*((4/nu)^(2/3)), nu >= 4 */
209 static const double coef_jnu4_b[] = {
233 /* Chebyshev expansion: j_{nu,5} = c_k T_k*(nu/5), nu <= 5 */
234 static const double coef_jnu5_a[] = {
257 /* Chebyshev expansion: j_{nu,5} = nu c_k T_k*((5/nu)^(2/3)), nu >= 5 */
258 /* FIXME: There is something wrong with this fit, in about the
259 * 9th or 10th decimal place.
261 static const double coef_jnu5_b[] = {
284 /* Chebyshev expansion: j_{nu,6} = c_k T_k*(nu/6), nu <= 6 */
285 static const double coef_jnu6_a[] = {
308 /* Chebyshev expansion: j_{nu,6} = nu c_k T_k*((6/nu)^(2/3)), nu >= 6 */
309 static const double coef_jnu6_b[] = {
332 /* Chebyshev expansion: j_{nu,7} = c_k T_k*(nu/7), nu <= 7 */
333 static const double coef_jnu7_a[] = {
356 /* Chebyshev expansion: j_{nu,7} = nu c_k T_k*((7/nu)^(2/3)), nu >= 7 */
357 static const double coef_jnu7_b[] = {
380 /* Chebyshev expansion: j_{nu,8} = c_k T_k*(nu/8), nu <= 8 */
381 static const double coef_jnu8_a[] = {
404 /* Chebyshev expansion: j_{nu,8} = nu c_k T_k*((8/nu)^(2/3)), nu >= 8 */
405 static const double coef_jnu8_b[] = {
428 /* Chebyshev expansion: j_{nu,9} = c_k T_k*(nu/9), nu <= 9 */
429 static const double coef_jnu9_a[] = {
452 /* Chebyshev expansion: j_{nu,9} = nu c_k T_k*((9/nu)^(2/3)), nu >= 9 */
453 static const double coef_jnu9_b[] = {
476 /* Chebyshev expansion: j_{nu,10} = c_k T_k*(nu/10), nu <= 10 */
477 static const double coef_jnu10_a[] = {
501 /* Chebyshev expansion: j_{nu,10} = nu c_k T_k*((10/nu)^(2/3)), nu >= 10 */
502 static const double coef_jnu10_b[] = {
525 /* Chebyshev expansion: j_{nu,11} = c_k T_k*(nu/22), nu <= 22 */
526 static const double coef_jnu11_a[] = {
528 15.33692279367165101,
529 -0.33677234163517130,
531 -0.00781084960665093,
533 -0.00029695043846867,
535 -0.00001370575125628,
557 /* Chebyshev expansion: j_{nu,12} = c_k T_k*(nu/24), nu <= 24 */
558 static const double coef_jnu12_a[] = {
561 -0.36718411124537953,
563 -0.00849884978867533,
565 -0.00032248114889921,
567 -0.00001485665901339,
589 /* Chebyshev expansion: j_{nu,13} = c_k T_k*(nu/26), nu <= 26 */
590 static const double coef_jnu13_a[] = {
593 -0.39759381380126650,
595 -0.00918674227679980,
597 -0.00034800528297612,
599 -0.00001600713368099,
624 /* Chebyshev expansion: j_{nu,14} = c_k T_k*(nu/28), nu <= 28 */
625 static const double coef_jnu14_a[] = {
628 -0.42800190567884337,
630 -0.00987455163523582,
632 -0.00037352439419968,
634 -0.00001715728110045,
655 /* Chebyshev expansion: j_{nu,15} = c_k T_k*(nu/30), nu <= 30 */
656 static const double coef_jnu15_a[] = {
659 -0.45840871823085836,
661 -0.01056229551143042,
663 -0.00039903958650729,
665 -0.00001830717574922,
686 /* Chebyshev expansion: j_{nu,16} = c_k T_k*(nu/32), nu <= 32 */
687 static const double coef_jnu16_a[] = {
689 22.32040402918608585,
690 -0.48881449782358690,
692 -0.01124998690363398,
694 -0.00042455166484632,
696 -0.00001945687139551,
717 /* Chebyshev expansion: j_{nu,17} = c_k T_k*(nu/34), nu <= 34 */
718 static const double coef_jnu17_a[] = {
720 23.71708159112252670,
721 -0.51921943142405352,
723 -0.01193763559341369,
725 -0.00045006122941781,
727 -0.00002060640777107,
748 /* Chebyshev expansion: j_{nu,18} = c_k T_k*(nu/36), nu <= 36 */
749 static const double coef_jnu18_a[] = {
751 25.11375537470259305,
752 -0.54962366347317668,
754 -0.01262524908033818,
756 -0.00047556873651929,
758 -0.00002175581482429,
779 /* Chebyshev expansion: j_{nu,19} = c_k T_k*(nu/38), nu <= 38 */
780 static const double coef_jnu19_a[] = {
782 26.51042598308271729,
783 -0.58002730731948358,
785 -0.01331283320930301,
787 -0.00050107453900793,
789 -0.00002290511552874,
810 /* Chebyshev expansion: j_{nu,20} = c_k T_k*(nu/40), nu <= 40 */
811 static const double coef_jnu20_a[] = {
814 -0.61043045315390591,
816 -0.01400039260208282,
818 -0.00052657891389470,
820 -0.00002405432778364,
842 static const double * coef_jnu_a[] = {
866 static const size_t size_jnu_a[] = {
868 sizeof(coef_jnu1_a)/sizeof(double),
869 sizeof(coef_jnu2_a)/sizeof(double),
870 sizeof(coef_jnu3_a)/sizeof(double),
871 sizeof(coef_jnu4_a)/sizeof(double),
872 sizeof(coef_jnu5_a)/sizeof(double),
873 sizeof(coef_jnu6_a)/sizeof(double),
874 sizeof(coef_jnu7_a)/sizeof(double),
875 sizeof(coef_jnu8_a)/sizeof(double),
876 sizeof(coef_jnu9_a)/sizeof(double),
877 sizeof(coef_jnu10_a)/sizeof(double),
878 sizeof(coef_jnu11_a)/sizeof(double),
879 sizeof(coef_jnu12_a)/sizeof(double),
880 sizeof(coef_jnu13_a)/sizeof(double),
881 sizeof(coef_jnu14_a)/sizeof(double),
882 sizeof(coef_jnu15_a)/sizeof(double),
883 sizeof(coef_jnu16_a)/sizeof(double),
884 sizeof(coef_jnu17_a)/sizeof(double),
885 sizeof(coef_jnu18_a)/sizeof(double),
886 sizeof(coef_jnu19_a)/sizeof(double),
887 sizeof(coef_jnu20_a)/sizeof(double)
891 static const double * coef_jnu_b[] = {
905 static const size_t size_jnu_b[] = {
907 sizeof(coef_jnu1_b)/sizeof(double),
908 sizeof(coef_jnu2_b)/sizeof(double),
909 sizeof(coef_jnu3_b)/sizeof(double),
910 sizeof(coef_jnu4_b)/sizeof(double),
911 sizeof(coef_jnu5_b)/sizeof(double),
912 sizeof(coef_jnu6_b)/sizeof(double),
913 sizeof(coef_jnu7_b)/sizeof(double),
914 sizeof(coef_jnu8_b)/sizeof(double),
915 sizeof(coef_jnu9_b)/sizeof(double),
916 sizeof(coef_jnu10_b)/sizeof(double)
921 /* Evaluate Clenshaw recurrence for
922 * a T* Chebyshev series.
926 clenshaw(const double * c, int N, double u)
933 B_nm1 = 2.0*(2.0*u-1.0) * B_n - B_np1 + c[n-1];
937 return B_n - (2.0*u-1.0)*B_np1;
942 /* correction terms to leading McMahon expansion
943 * [Abramowitz+Stegun 9.5.12]
944 * [Olver, Royal Society Math. Tables, v. 7]
945 * We factor out a beta, so that this is a multiplicative
947 * j_{nu,s} = beta(s,nu) * mcmahon_correction(nu, beta(s,nu))
948 * macmahon_correction --> 1 as s --> Inf
951 mcmahon_correction(const double mu, const double beta)
953 const double eb = 8.0*beta;
954 const double ebsq = eb*eb;
956 if(mu < GSL_DBL_EPSILON) {
957 /* Prevent division by zero below. */
958 const double term1 = 1.0/ebsq;
959 const double term2 = -4.0*31.0/(3*ebsq*ebsq);
960 const double term3 = 32.0*3779.0/(15.0*ebsq*ebsq*ebsq);
961 const double term4 = -64.0*6277237.0/(105.0*ebsq*ebsq*ebsq*ebsq);
962 const double term5 = 512.0*2092163573.0/(315.0*ebsq*ebsq*ebsq*ebsq*ebsq);
963 return 1.0 + 8.0*(term1 + term2 + term3 + term4 + term5);
966 /* Here we do things in terms of 1/mu, which
967 * is purely to prevent overflow in the very
968 * unlikely case that mu is really big.
970 const double mi = 1.0/mu;
971 const double r = mu/ebsq;
972 const double n2 = 4.0/3.0 * (7.0 - 31.0*mi);
973 const double n3 = 32.0/15.0 * (83.0 + (-982.0 + 3779.0*mi)*mi);
974 const double n4 = 64.0/105.0 * (6949.0 + (-153855.0 + (1585743.0 - 6277237.0*mi)*mi)*mi);
975 const double n5 = 512.0/315.0 * (70197.0 + (-2479316.0 + (48010494.0 + (-512062548.0 + 2092163573.0*mi)*mi)*mi)*mi);
976 const double n6 = 2048.0/3465.0 * (5592657.0 + (-287149133.0 + (8903961290.0 + (-179289628602.0 + (1982611456181.0 - 8249725736393.0*mi)*mi)*mi)*mi)*mi);
977 const double term1 = (1.0 - mi) * r;
978 const double term2 = term1 * n2 * r;
979 const double term3 = term1 * n3 * r*r;
980 const double term4 = term1 * n4 * r*r*r;
981 const double term5 = term1 * n5 * r*r*r*r;
982 const double term6 = term1 * n6 * r*r*r*r*r;
983 return 1.0 - 8.0*(term1 + term2 + term3 + term4 + term5 + term6);
988 /* Assumes z >= 1.0 */
990 olver_b0(double z, double minus_zeta)
993 const double a = 1.0-z;
994 const double c0 = 0.0179988721413553309252458658183;
995 const double c1 = 0.0111992982212877614645974276203;
996 const double c2 = 0.0059404069786014304317781160605;
997 const double c3 = 0.0028676724516390040844556450173;
998 const double c4 = 0.0012339189052567271708525111185;
999 const double c5 = 0.0004169250674535178764734660248;
1000 const double c6 = 0.0000330173385085949806952777365;
1001 const double c7 = -0.0001318076238578203009990106425;
1002 const double c8 = -0.0001906870370050847239813945647;
1003 return c0 + a*(c1 + a*(c2 + a*(c3 + a*(c4 + a*(c5 + a*(c6 + a*(c7 + a*c8)))))));
1006 const double abs_zeta = minus_zeta;
1007 const double t = 1.0/(z*sqrt(1.0 - 1.0/(z*z)));
1008 return -5.0/(48.0*abs_zeta*abs_zeta) + t*(3.0 + 5.0*t*t)/(24.0*sqrt(abs_zeta));
1015 olver_f1(double z, double minus_zeta)
1017 const double b0 = olver_b0(z, minus_zeta);
1018 const double h2 = sqrt(4.0*minus_zeta/(z*z-1.0)); /* FIXME */
1019 return 0.5 * z * h2 * b0;
1024 gsl_sf_bessel_zero_J0_e(unsigned int s, gsl_sf_result * result)
1026 /* CHECK_POINTER(result) */
1031 GSL_ERROR ("error", GSL_EINVAL);
1034 /* See [F. Lether, J. Comp. Appl .Math. 67, 167 (1996)]. */
1036 static const double P[] = { 1567450796.0/12539606369.0,
1037 8903660.0/2365861.0,
1038 10747040.0/536751.0,
1039 17590991.0/1696654.0
1041 static const double Q[] = { 1.0,
1042 29354255.0/954518.0,
1043 76900001.0/431847.0,
1047 const double beta = (s - 0.25) * M_PI;
1048 const double bi2 = 1.0/(beta*beta);
1049 const double R33num = P[0] + bi2 * (P[1] + bi2 * (P[2] + P[3] * bi2));
1050 const double R33den = Q[0] + bi2 * (Q[1] + bi2 * (Q[2] + Q[3] * bi2));
1051 const double R33 = R33num/R33den;
1052 result->val = beta + R33/beta;
1053 result->err = fabs(3.0e-15 * result->val);
1060 gsl_sf_bessel_zero_J1_e(unsigned int s, gsl_sf_result * result)
1062 /* CHECK_POINTER(result) */
1070 /* See [M. Branders et al., J. Comp. Phys. 42, 403 (1981)]. */
1072 static const double a[] = { -0.362804405737084,
1074 0.439454547101171e-01,
1075 0.159340088474713e-02
1077 static const double b[] = { 1.0,
1080 -0.424906902601794e-02
1083 const double beta = (s + 0.25) * M_PI;
1084 const double bi2 = 1.0/(beta*beta);
1085 const double Rnum = a[3] + bi2 * (a[2] + bi2 * (a[1] + bi2 * a[0]));
1086 const double Rden = b[3] + bi2 * (b[2] + bi2 * (b[1] + bi2 * b[0]));
1087 const double R = Rnum/Rden;
1088 result->val = beta * (1.0 + R*bi2);
1089 result->err = fabs(2.0e-14 * result->val);
1096 gsl_sf_bessel_zero_Jnu_e(double nu, unsigned int s, gsl_sf_result * result)
1098 /* CHECK_POINTER(result) */
1101 DOMAIN_ERROR(result);
1107 GSL_ERROR ("no zero-th root for nu = 0.0", GSL_EINVAL);
1112 /* This can be done, I'm just lazy now. */
1115 GSL_ERROR("unimplemented", GSL_EUNIMPL);
1118 /* Chebyshev fits for the first positive zero.
1119 * For some reason Nemeth made this different from the others.
1122 const double * c = coef_jnu_a[s];
1123 const size_t L = size_jnu_a[s];
1124 const double arg = nu/2.0;
1125 const double chb = clenshaw(c, L-1, arg);
1127 result->err = 2.0e-15 * result->val;
1130 const double * c = coef_jnu_b[s];
1131 const size_t L = size_jnu_b[s];
1132 const double arg = pow(2.0/nu, 2.0/3.0);
1133 const double chb = clenshaw(c, L-1, arg);
1134 result->val = nu * chb;
1135 result->err = 2.0e-15 * result->val;
1140 /* Chebyshev fits for the first 10 positive zeros. */
1142 const double * c = coef_jnu_a[s];
1143 const size_t L = size_jnu_a[s];
1144 const double arg = nu/s;
1145 const double chb = clenshaw(c, L-1, arg);
1147 result->err = 2.0e-15 * result->val;
1150 const double * c = coef_jnu_b[s];
1151 const size_t L = size_jnu_b[s];
1152 const double arg = pow(s/nu, 2.0/3.0);
1153 const double chb = clenshaw(c, L-1, arg);
1154 result->val = nu * chb;
1155 result->err = 2.0e-15 * result->val;
1157 /* FIXME: truth in advertising for the screwed up
1158 * s = 5 fit. Need to fix that.
1161 result->err *= 5.0e+06;
1166 else if(s > 0.5*nu && s <= 20) {
1167 /* Chebyshev fits for 10 < s <= 20. */
1168 const double * c = coef_jnu_a[s];
1169 const size_t L = size_jnu_a[s];
1170 const double arg = nu/(2.0*s);
1171 const double chb = clenshaw(c, L-1, arg);
1173 result->err = 4.0e-15 * chb;
1176 else if(s > 2.0 * nu) {
1177 /* McMahon expansion if s is large compared to nu. */
1178 const double beta = (s + 0.5*nu - 0.25) * M_PI;
1179 const double mc = mcmahon_correction(4.0*nu*nu, beta);
1180 gsl_sf_result rat12;
1181 gsl_sf_pow_int_e(nu/beta, 14, &rat12);
1182 result->val = beta * mc;
1183 result->err = 4.0 * fabs(beta) * rat12.val;
1184 result->err += 4.0 * fabs(GSL_DBL_EPSILON * result->val);
1188 /* Olver uniform asymptotic. */
1190 const int stat_as = gsl_sf_airy_zero_Ai_e(s, &as);
1191 const double minus_zeta = -pow(nu,-2.0/3.0) * as.val;
1192 const double z = gsl_sf_bessel_Olver_zofmzeta(minus_zeta);
1193 const double f1 = olver_f1(z, minus_zeta);
1194 result->val = nu * (z + f1/(nu*nu));
1195 result->err = 0.001/(nu*nu*nu);
1196 result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
1202 /*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/
1206 double gsl_sf_bessel_zero_J0(unsigned int s)
1208 EVAL_RESULT(gsl_sf_bessel_zero_J0_e(s, &result));
1211 double gsl_sf_bessel_zero_J1(unsigned int s)
1213 EVAL_RESULT(gsl_sf_bessel_zero_J1_e(s, &result));
1216 double gsl_sf_bessel_zero_Jnu(double nu, unsigned int s)
1218 EVAL_RESULT(gsl_sf_bessel_zero_Jnu_e(nu, s, &result));