/* Evaluate J_mu(x),J_{mu+1}(x) and Y_mu(x),Y_{mu+1}(x) for |mu| < 1/2 */ int gsl_sf_bessel_JY_mu_restricted(const double mu, const double x, gsl_sf_result * Jmu, gsl_sf_result * Jmup1, gsl_sf_result * Ymu, gsl_sf_result * Ymup1) { /* CHECK_POINTER(Jmu) */ /* CHECK_POINTER(Jmup1) */ /* CHECK_POINTER(Ymu) */ /* CHECK_POINTER(Ymup1) */ if(x < 0.0 || fabs(mu) > 0.5) { Jmu->val = 0.0; Jmu->err = 0.0; Jmup1->val = 0.0; Jmup1->err = 0.0; Ymu->val = 0.0; Ymu->err = 0.0; Ymup1->val = 0.0; Ymup1->err = 0.0; GSL_ERROR ("error", GSL_EDOM); } else if(x == 0.0) { if(mu == 0.0) { Jmu->val = 1.0; Jmu->err = 0.0; } else { Jmu->val = 0.0; Jmu->err = 0.0; } Jmup1->val = 0.0; Jmup1->err = 0.0; Ymu->val = 0.0; Ymu->err = 0.0; Ymup1->val = 0.0; Ymup1->err = 0.0; GSL_ERROR ("error", GSL_EDOM); } else { int stat_Y; int stat_J; if(x < 2.0) { /* Use Taylor series for J and the Temme series for Y. * The Taylor series for J requires nu > 0, so we shift * up one and use the recursion relation to get Jmu, in * case mu < 0. */ gsl_sf_result Jmup2; int stat_J1 = gsl_sf_bessel_IJ_taylor_e(mu+1.0, x, -1, 100, GSL_DBL_EPSILON, Jmup1); int stat_J2 = gsl_sf_bessel_IJ_taylor_e(mu+2.0, x, -1, 100, GSL_DBL_EPSILON, &Jmup2); double c = 2.0*(mu+1.0)/x; Jmu->val = c * Jmup1->val - Jmup2.val; Jmu->err = c * Jmup1->err + Jmup2.err; Jmu->err += 2.0 * GSL_DBL_EPSILON * fabs(Jmu->val); stat_J = GSL_ERROR_SELECT_2(stat_J1, stat_J2); stat_Y = gsl_sf_bessel_Y_temme(mu, x, Ymu, Ymup1); return GSL_ERROR_SELECT_2(stat_J, stat_Y); } else if(x < 1000.0) { double P, Q; double J_ratio; double J_sgn; const int stat_CF1 = gsl_sf_bessel_J_CF1(mu, x, &J_ratio, &J_sgn); const int stat_CF2 = gsl_sf_bessel_JY_steed_CF2(mu, x, &P, &Q); double Jprime_J_ratio = mu/x - J_ratio; double gamma = (P - Jprime_J_ratio)/Q; Jmu->val = J_sgn * sqrt(2.0/(M_PI*x) / (Q + gamma*(P-Jprime_J_ratio))); Jmu->err = 4.0 * GSL_DBL_EPSILON * fabs(Jmu->val); Jmup1->val = J_ratio * Jmu->val; Jmup1->err = fabs(J_ratio) * Jmu->err; Ymu->val = gamma * Jmu->val; Ymu->err = fabs(gamma) * Jmu->err; Ymup1->val = Ymu->val * (mu/x - P - Q/gamma); Ymup1->err = Ymu->err * fabs(mu/x - P - Q/gamma) + 4.0*GSL_DBL_EPSILON*fabs(Ymup1->val); return GSL_ERROR_SELECT_2(stat_CF1, stat_CF2); } else { /* Use asymptotics for large argument. */ const int stat_J0 = gsl_sf_bessel_Jnu_asympx_e(mu, x, Jmu); const int stat_J1 = gsl_sf_bessel_Jnu_asympx_e(mu+1.0, x, Jmup1); const int stat_Y0 = gsl_sf_bessel_Ynu_asympx_e(mu, x, Ymu); const int stat_Y1 = gsl_sf_bessel_Ynu_asympx_e(mu+1.0, x, Ymup1); stat_J = GSL_ERROR_SELECT_2(stat_J0, stat_J1); stat_Y = GSL_ERROR_SELECT_2(stat_Y0, stat_Y1); return GSL_ERROR_SELECT_2(stat_J, stat_Y); } } }
int gsl_sf_bessel_jl_e(const int l, const double x, gsl_sf_result * result) { if(l < 0 || x < 0.0) { DOMAIN_ERROR(result); } else if(x == 0.0) { result->val = ( l > 0 ? 0.0 : 1.0 ); result->err = 0.0; return GSL_SUCCESS; } else if(l == 0) { return gsl_sf_bessel_j0_e(x, result); } else if(l == 1) { return gsl_sf_bessel_j1_e(x, result); } else if(l == 2) { return gsl_sf_bessel_j2_e(x, result); } else if(x*x < 10.0*(l+0.5)/M_E) { gsl_sf_result b; int status = gsl_sf_bessel_IJ_taylor_e(l+0.5, x, -1, 50, GSL_DBL_EPSILON, &b); double pre = sqrt((0.5*M_PI)/x); result->val = pre * b.val; result->err = pre * b.err; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return status; } else if(GSL_ROOT4_DBL_EPSILON * x > (l*l + l + 1.0)) { gsl_sf_result b; int status = gsl_sf_bessel_Jnu_asympx_e(l + 0.5, x, &b); double pre = sqrt((0.5*M_PI)/x); result->val = pre * b.val; result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val) + pre * b.err; return status; } else if(l > 1.0/GSL_ROOT6_DBL_EPSILON) { gsl_sf_result b; int status = gsl_sf_bessel_Jnu_asymp_Olver_e(l + 0.5, x, &b); double pre = sqrt((0.5*M_PI)/x); result->val = pre * b.val; result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val) + pre * b.err; return status; } else if(x > 1000.0 && x > l*l) { /* We need this path to avoid feeding large x to CF1 below; */ gsl_sf_result b; int status = gsl_sf_bessel_Jnu_asympx_e(l + 0.5, x, &b); double pre = sqrt((0.5*M_PI)/x); result->val = pre * b.val; result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val) + pre * b.err; return status; } else { double sgn; double ratio; /* The CF1 call will hit 10000 iterations for x > 10000 + l */ int stat_CF1 = gsl_sf_bessel_J_CF1(l+0.5, x, &ratio, &sgn); double jellp1 = GSL_SQRT_DBL_EPSILON * ratio; double jell = GSL_SQRT_DBL_EPSILON; double jellm1; int ell; for(ell = l; ell > 0; ell--) { jellm1 = -jellp1 + (2*ell + 1)/x * jell; jellp1 = jell; jell = jellm1; } if(fabs(jell) > fabs(jellp1)) { gsl_sf_result j0_result; int stat_j0 = gsl_sf_bessel_j0_e(x, &j0_result); double pre = GSL_SQRT_DBL_EPSILON / jell; result->val = j0_result.val * pre; result->err = j0_result.err * fabs(pre); result->err += 4.0 * GSL_DBL_EPSILON * (0.5*l + 1.0) * fabs(result->val); return GSL_ERROR_SELECT_2(stat_j0, stat_CF1); } else { gsl_sf_result j1_result; int stat_j1 = gsl_sf_bessel_j1_e(x, &j1_result); double pre = GSL_SQRT_DBL_EPSILON / jellp1; result->val = j1_result.val * pre; result->err = j1_result.err * fabs(pre); result->err += 4.0 * GSL_DBL_EPSILON * (0.5*l + 1.0) * fabs(result->val); return GSL_ERROR_SELECT_2(stat_j1, stat_CF1); } } }
int gsl_sf_bessel_Jn_e(int n, double x, gsl_sf_result * result) { int sign = 1; if(n < 0) { /* reduce to case n >= 0 */ n = -n; if(GSL_IS_ODD(n)) sign = -sign; } if(x < 0.0) { /* reduce to case x >= 0. */ x = -x; if(GSL_IS_ODD(n)) sign = -sign; } /* CHECK_POINTER(result) */ if(n == 0) { gsl_sf_result b0; int stat_J0 = gsl_sf_bessel_J0_e(x, &b0); result->val = sign * b0.val; result->err = b0.err; return stat_J0; } else if(n == 1) { gsl_sf_result b1; int stat_J1 = gsl_sf_bessel_J1_e(x, &b1); result->val = sign * b1.val; result->err = b1.err; return stat_J1; } else { if(x == 0.0) { result->val = 0.0; result->err = 0.0; return GSL_SUCCESS; } else if(x*x < 10.0*(n+1.0)*GSL_ROOT5_DBL_EPSILON) { gsl_sf_result b; int status = gsl_sf_bessel_IJ_taylor_e((double)n, x, -1, 50, GSL_DBL_EPSILON, &b); result->val = sign * b.val; result->err = b.err; result->err += GSL_DBL_EPSILON * fabs(result->val); return status; } else if(GSL_ROOT3_DBL_EPSILON * x > (n*n+1.0)) { int status = gsl_sf_bessel_Jnu_asympx_e((double)n, x, result); result->val *= sign; return status; } else if(n > 50) { int status = gsl_sf_bessel_Jnu_asymp_Olver_e((double)n, x, result); result->val *= sign; return status; } else { double ans; double err; double ratio; double sgn; int stat_b; int stat_CF1 = gsl_sf_bessel_J_CF1((double)n, x, &ratio, &sgn); /* backward recurrence */ double Jkp1 = GSL_SQRT_DBL_MIN * ratio; double Jk = GSL_SQRT_DBL_MIN; double Jkm1; int k; for(k=n; k>0; k--) { Jkm1 = 2.0*k/x * Jk - Jkp1; Jkp1 = Jk; Jk = Jkm1; } if(fabs(Jkp1) > fabs(Jk)) { gsl_sf_result b1; stat_b = gsl_sf_bessel_J1_e(x, &b1); ans = b1.val/Jkp1 * GSL_SQRT_DBL_MIN; err = b1.err/Jkp1 * GSL_SQRT_DBL_MIN; } else { gsl_sf_result b0; stat_b = gsl_sf_bessel_J0_e(x, &b0); ans = b0.val/Jk * GSL_SQRT_DBL_MIN; err = b0.err/Jk * GSL_SQRT_DBL_MIN; } result->val = sign * ans; result->err = fabs(err); return GSL_ERROR_SELECT_2(stat_CF1, stat_b); } } }
int gsl_sf_bessel_Jnu_e(const double nu, const double x, gsl_sf_result * result) { /* CHECK_POINTER(result) */ if(x < 0.0 || nu < 0.0) { DOMAIN_ERROR(result); } else if(x == 0.0) { if(nu == 0.0) { result->val = 1.0; result->err = 0.0; } else { result->val = 0.0; result->err = 0.0; } return GSL_SUCCESS; } else if(x*x < 10.0*(nu+1.0)) { return gsl_sf_bessel_IJ_taylor_e(nu, x, -1, 100, GSL_DBL_EPSILON, result); } else if(nu > 50.0) { return gsl_sf_bessel_Jnu_asymp_Olver_e(nu, x, result); } else { /* -1/2 <= mu <= 1/2 */ int N = (int)(nu + 0.5); double mu = nu - N; /* Determine the J ratio at nu. */ double Jnup1_Jnu; double sgn_Jnu; const int stat_CF1 = gsl_sf_bessel_J_CF1(nu, x, &Jnup1_Jnu, &sgn_Jnu); if(x < 2.0) { /* Determine Y_mu, Y_mup1 directly and recurse forward to nu. * Then use the CF1 information to solve for J_nu and J_nup1. */ gsl_sf_result Y_mu, Y_mup1; const int stat_mu = gsl_sf_bessel_Y_temme(mu, x, &Y_mu, &Y_mup1); double Ynm1 = Y_mu.val; double Yn = Y_mup1.val; double Ynp1 = 0.0; int n; for(n=1; n<N; n++) { Ynp1 = 2.0*(mu+n)/x * Yn - Ynm1; Ynm1 = Yn; Yn = Ynp1; } result->val = 2.0/(M_PI*x) / (Jnup1_Jnu*Yn - Ynp1); result->err = GSL_DBL_EPSILON * (N + 2.0) * fabs(result->val); return GSL_ERROR_SELECT_2(stat_mu, stat_CF1); } else { /* Recurse backward from nu to mu, determining the J ratio * at mu. Use this together with a Steed method CF2 to * determine the actual J_mu, and thus obtain the normalization. */ double Jmu; double Jmup1_Jmu; double sgn_Jmu; double Jmuprime_Jmu; double P, Q; const int stat_CF2 = gsl_sf_bessel_JY_steed_CF2(mu, x, &P, &Q); double gamma; double Jnp1 = sgn_Jnu * GSL_SQRT_DBL_MIN * Jnup1_Jnu; double Jn = sgn_Jnu * GSL_SQRT_DBL_MIN; double Jnm1; int n; for(n=N; n>0; n--) { Jnm1 = 2.0*(mu+n)/x * Jn - Jnp1; Jnp1 = Jn; Jn = Jnm1; } Jmup1_Jmu = Jnp1/Jn; sgn_Jmu = GSL_SIGN(Jn); Jmuprime_Jmu = mu/x - Jmup1_Jmu; gamma = (P - Jmuprime_Jmu)/Q; Jmu = sgn_Jmu * sqrt(2.0/(M_PI*x) / (Q + gamma*(P-Jmuprime_Jmu))); result->val = Jmu * (sgn_Jnu * GSL_SQRT_DBL_MIN) / Jn; result->err = 2.0 * GSL_DBL_EPSILON * (N + 2.0) * fabs(result->val); return GSL_ERROR_SELECT_2(stat_CF2, stat_CF1); } } }