static int bessel_J_recur_asymp(const double nu, const double x, gsl_sf_result * Jnu, gsl_sf_result * Jnup1) { const double nu_cut = 25.0; int n; int steps = ceil(nu_cut - nu) + 1; gsl_sf_result r_Jnp1; gsl_sf_result r_Jn; int stat_O1 = gsl_sf_bessel_Jnu_asymp_Olver_e(nu + steps + 1.0, x, &r_Jnp1); int stat_O2 = gsl_sf_bessel_Jnu_asymp_Olver_e(nu + steps, x, &r_Jn); double r_fe = fabs(r_Jnp1.err/r_Jnp1.val) + fabs(r_Jn.err/r_Jn.val); double Jnp1 = r_Jnp1.val; double Jn = r_Jn.val; double Jnm1; double Jnp1_save; for(n=steps; n>0; n--) { Jnm1 = 2.0*(nu+n)/x * Jn - Jnp1; Jnp1 = Jn; Jnp1_save = Jn; Jn = Jnm1; } Jnu->val = Jn; Jnu->err = (r_fe + GSL_DBL_EPSILON * (steps + 1.0)) * fabs(Jn); Jnup1->val = Jnp1_save; Jnup1->err = (r_fe + GSL_DBL_EPSILON * (steps + 1.0)) * fabs(Jnp1_save); return GSL_ERROR_SELECT_2(stat_O1, stat_O2); }
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_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_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); } } }