/* the full definition of C_L(eta) for any valid L and eta * [Abramowitz and Stegun 14.1.7] * This depends on the complex gamma function. For large * arguments the phase of the complex gamma function is not * very accurately determined. However the modulus is, and that * is all that we need to calculate C_L. * * This is not valid for L <= -3/2 or L = -1. */ static int CLeta(double L, double eta, gsl_sf_result * result) { gsl_sf_result ln1; /* log of numerator Gamma function */ gsl_sf_result ln2; /* log of denominator Gamma function */ double sgn = 1.0; double arg_val, arg_err; if(fabs(eta/(L+1.0)) < GSL_DBL_EPSILON) { gsl_sf_lngamma_e(L+1.0, &ln1); } else { gsl_sf_result p1; /* phase of numerator Gamma -- not used */ gsl_sf_lngamma_complex_e(L+1.0, eta, &ln1, &p1); /* should be ok */ } gsl_sf_lngamma_e(2.0*(L+1.0), &ln2); if(L < -1.0) sgn = -sgn; arg_val = L*M_LN2 - 0.5*eta*M_PI + ln1.val - ln2.val; arg_err = ln1.err + ln2.err; arg_err += GSL_DBL_EPSILON * (fabs(L*M_LN2) + fabs(0.5*eta*M_PI)); return gsl_sf_exp_err_e(arg_val, arg_err, result); }
/* The dominant part, * D(a,x) := x^a e^(-x) / Gamma(a+1) */ static int gamma_inc_D(const double a, const double x, gsl_sf_result * result) { if(a < 10.0) { double lnr; gsl_sf_result lg; gsl_sf_lngamma_e(a+1.0, &lg); lnr = a * log(x) - x - lg.val; result->val = exp(lnr); result->err = 2.0 * GSL_DBL_EPSILON * (fabs(lnr) + 1.0) * fabs(result->val); return GSL_SUCCESS; } else { double mu = (x-a)/a; double term1; gsl_sf_result gstar; gsl_sf_result ln_term; gsl_sf_log_1plusx_mx_e(mu, &ln_term); /* log(1+mu) - mu */ gsl_sf_gammastar_e(a, &gstar); term1 = exp(a*ln_term.val)/sqrt(2.0*M_PI*a); result->val = term1/gstar.val; result->err = 2.0 * GSL_DBL_EPSILON * (fabs(a*ln_term.val) + 1.0) * fabs(result->val); result->err += gstar.err/fabs(gstar.val) * fabs(result->val); return GSL_SUCCESS; } }
int gsl_sf_bessel_lnKnu_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(nu == 0.0) { gsl_sf_result K_scaled; /* This cannot underflow, and * it will not throw GSL_EDOM * since that is already checked. */ gsl_sf_bessel_K0_scaled_e(x, &K_scaled); result->val = -x + log(fabs(K_scaled.val)); result->err = GSL_DBL_EPSILON * fabs(x) + fabs(K_scaled.err/K_scaled.val); result->err += GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } else if(x < 2.0 && nu > 1.0) { /* Make use of the inequality * Knu(x) <= 1/2 (2/x)^nu Gamma(nu), * which follows from the integral representation * [Abramowitz+Stegun, 9.6.23 (2)]. With this * we decide whether or not there is an overflow * problem because x is small. */ double ln_bound; gsl_sf_result lg_nu; gsl_sf_lngamma_e(nu, &lg_nu); ln_bound = -M_LN2 - nu*log(0.5*x) + lg_nu.val; if(ln_bound > GSL_LOG_DBL_MAX - 20.0) { /* x must be very small or nu very large (or both). */ double xi = 0.25*x*x; double sum = 1.0 - xi/(nu-1.0); if(nu > 2.0) sum += (xi/(nu-1.0)) * (xi/(nu-2.0)); result->val = ln_bound + log(sum); result->err = lg_nu.err; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } /* can drop-through here */ } { /* We passed the above tests, so no problem. * Evaluate as usual. Note the possible drop-through * in the above code! */ gsl_sf_result K_scaled; gsl_sf_bessel_Knu_scaled_e(nu, x, &K_scaled); result->val = -x + log(fabs(K_scaled.val)); result->err = GSL_DBL_EPSILON * fabs(x) + fabs(K_scaled.err/K_scaled.val); result->err += GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } }
/// Log lower Pochhammer symbol. double lpochhammer_l(double a, double x) { if (a == x) return std::numeric_limits<double>::infinity(); gsl_sf_result result_num; int stat_num = gsl_sf_lngamma_e(std::abs(a - x), &result_num); gsl_sf_result result_den; int stat_den = gsl_sf_lngamma_e(std::abs(a), &result_den); if (stat_num != GSL_SUCCESS && stat_den != GSL_SUCCESS) { std::ostringstream msg("Error in lpochhammer_l:"); msg << " a=" << a << " x=" << x; throw std::runtime_error(msg.str()); } else return result_num.val - result_den.val; }
int gsl_sf_hyperg_2F1_conj_renorm_e(const double aR, const double aI, const double c, const double x, gsl_sf_result * result ) { const double rintc = floor(c + 0.5); const double rinta = floor(aR + 0.5); const int a_neg_integer = ( aR < 0.0 && fabs(aR-rinta) < locEPS && aI == 0.0); const int c_neg_integer = ( c < 0.0 && fabs(c - rintc) < locEPS ); if(c_neg_integer) { if(a_neg_integer && aR > c+0.1) { /* 2F1 terminates early */ result->val = 0.0; result->err = 0.0; return GSL_SUCCESS; } else { /* 2F1 does not terminate early enough, so something survives */ /* [Abramowitz+Stegun, 15.1.2] */ gsl_sf_result g1, g2; gsl_sf_result g3; gsl_sf_result a1, a2; int stat = 0; stat += gsl_sf_lngamma_complex_e(aR-c+1, aI, &g1, &a1); stat += gsl_sf_lngamma_complex_e(aR, aI, &g2, &a2); stat += gsl_sf_lngamma_e(-c+2.0, &g3); if(stat != 0) { DOMAIN_ERROR(result); } else { gsl_sf_result F; int stat_F = gsl_sf_hyperg_2F1_conj_e(aR-c+1, aI, -c+2, x, &F); double ln_pre_val = 2.0*(g1.val - g2.val) - g3.val; double ln_pre_err = 2.0 * (g1.err + g2.err) + g3.err; int stat_e = gsl_sf_exp_mult_err_e(ln_pre_val, ln_pre_err, F.val, F.err, result); return GSL_ERROR_SELECT_2(stat_e, stat_F); } } } else { /* generic c */ gsl_sf_result F; gsl_sf_result lng; double sgn; int stat_g = gsl_sf_lngamma_sgn_e(c, &lng, &sgn); int stat_F = gsl_sf_hyperg_2F1_conj_e(aR, aI, c, x, &F); int stat_e = gsl_sf_exp_mult_err_e(-lng.val, lng.err, sgn*F.val, F.err, result); return GSL_ERROR_SELECT_3(stat_e, stat_F, stat_g); } }
/* asymptotic expansion * j + 2.0 > 0.0 */ static int fd_asymp(const double j, const double x, gsl_sf_result * result) { const int j_integer = ( fabs(j - floor(j+0.5)) < 100.0*GSL_DBL_EPSILON ); const int itmax = 200; gsl_sf_result lg; int stat_lg = gsl_sf_lngamma_e(j + 2.0, &lg); double seqn_val = 0.5; double seqn_err = 0.0; double xm2 = (1.0/x)/x; double xgam = 1.0; double add = GSL_DBL_MAX; double cos_term; double ln_x; double ex_term_1; double ex_term_2; gsl_sf_result fneg; gsl_sf_result ex_arg; gsl_sf_result ex; int stat_fneg; int stat_e; int n; for(n=1; n<=itmax; n++) { double add_previous = add; gsl_sf_result eta; gsl_sf_eta_int_e(2*n, &eta); xgam = xgam * xm2 * (j + 1.0 - (2*n-2)) * (j + 1.0 - (2*n-1)); add = eta.val * xgam; if(!j_integer && fabs(add) > fabs(add_previous)) break; if(fabs(add/seqn_val) < GSL_DBL_EPSILON) break; seqn_val += add; seqn_err += 2.0 * GSL_DBL_EPSILON * fabs(add); } seqn_err += fabs(add); stat_fneg = fd_neg(j, -x, &fneg); ln_x = log(x); ex_term_1 = (j+1.0)*ln_x; ex_term_2 = lg.val; ex_arg.val = ex_term_1 - ex_term_2; /*(j+1.0)*ln_x - lg.val; */ ex_arg.err = GSL_DBL_EPSILON*(fabs(ex_term_1) + fabs(ex_term_2)) + lg.err; stat_e = gsl_sf_exp_err_e(ex_arg.val, ex_arg.err, &ex); cos_term = cos(j*M_PI); result->val = cos_term * fneg.val + 2.0 * seqn_val * ex.val; result->err = fabs(2.0 * ex.err * seqn_val); result->err += fabs(2.0 * ex.val * seqn_err); result->err += fabs(cos_term) * fneg.err; result->err += 4.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_ERROR_SELECT_3(stat_e, stat_fneg, stat_lg); }
/* Calculate series for small eta*lambda. * Assumes eta > 0, lambda != 0. * * This is just the defining hypergeometric for the Legendre function. * * P^{mu}_{-1/2 + I lam}(z) = 1/Gamma(l+3/2) ((z+1)/(z-1)^(mu/2) * 2F1(1/2 - I lam, 1/2 + I lam; l+3/2; (1-z)/2) * We use * z = cosh(eta) * (z-1)/2 = sinh^2(eta/2) * * And recall * H3d = sqrt(Pi Norm /(2 lam^2 sinh(eta))) P^{-l-1/2}_{-1/2 + I lam}(cosh(eta)) */ static int legendre_H3d_series(const int ell, const double lambda, const double eta, gsl_sf_result * result) { const int nmax = 5000; const double shheta = sinh(0.5*eta); const double ln_zp1 = M_LN2 + log(1.0 + shheta*shheta); const double ln_zm1 = M_LN2 + 2.0*log(shheta); const double zeta = -shheta*shheta; gsl_sf_result lg_lp32; double term = 1.0; double sum = 1.0; double sum_err = 0.0; gsl_sf_result lnsheta; double lnN; double lnpre_val, lnpre_err, lnprepow; int stat_e; int n; gsl_sf_lngamma_e(ell + 3.0/2.0, &lg_lp32); gsl_sf_lnsinh_e(eta, &lnsheta); legendre_H3d_lnnorm(ell, lambda, &lnN); lnprepow = 0.5*(ell + 0.5) * (ln_zm1 - ln_zp1); lnpre_val = lnprepow + 0.5*(lnN + M_LNPI - M_LN2 - lnsheta.val) - lg_lp32.val - log(fabs(lambda)); lnpre_err = lnsheta.err + lg_lp32.err + GSL_DBL_EPSILON * fabs(lnpre_val); lnpre_err += 2.0*GSL_DBL_EPSILON * (fabs(lnN) + M_LNPI + M_LN2); lnpre_err += 2.0*GSL_DBL_EPSILON * (0.5*(ell + 0.5) * (fabs(ln_zm1) + fabs(ln_zp1))); for(n=1; n<nmax; n++) { double aR = n - 0.5; term *= (aR*aR + lambda*lambda)*zeta/(ell + n + 0.5)/n; sum += term; sum_err += 2.0*GSL_DBL_EPSILON*fabs(term); if(fabs(term/sum) < 2.0 * GSL_DBL_EPSILON) break; } stat_e = gsl_sf_exp_mult_err_e(lnpre_val, lnpre_err, sum, fabs(term)+sum_err, result); return GSL_ERROR_SELECT_2(stat_e, (n==nmax ? GSL_EMAXITER : GSL_SUCCESS)); }
int gsl_sf_bessel_IJ_taylor_e(const double nu, const double x, const int sign, const int kmax, const double threshold, gsl_sf_result * result ) { /* CHECK_POINTER(result) */ if(nu < 0.0 || x < 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 { gsl_sf_result prefactor; /* (x/2)^nu / Gamma(nu+1) */ gsl_sf_result sum; int stat_pre; int stat_sum; int stat_mul; if(nu == 0.0) { prefactor.val = 1.0; prefactor.err = 0.0; stat_pre = GSL_SUCCESS; } else if(nu < INT_MAX-1) { /* Separate the integer part and use * y^nu / Gamma(nu+1) = y^N /N! y^f / (N+1)_f, * to control the error. */ const int N = (int)floor(nu + 0.5); const double f = nu - N; gsl_sf_result poch_factor; gsl_sf_result tc_factor; const int stat_poch = gsl_sf_poch_e(N+1.0, f, &poch_factor); const int stat_tc = gsl_sf_taylorcoeff_e(N, 0.5*x, &tc_factor); const double p = pow(0.5*x,f); prefactor.val = tc_factor.val * p / poch_factor.val; prefactor.err = tc_factor.err * p / poch_factor.val; prefactor.err += fabs(prefactor.val) / poch_factor.val * poch_factor.err; prefactor.err += 2.0 * GSL_DBL_EPSILON * fabs(prefactor.val); stat_pre = GSL_ERROR_SELECT_2(stat_tc, stat_poch); } else { gsl_sf_result lg; const int stat_lg = gsl_sf_lngamma_e(nu+1.0, &lg); const double term1 = nu*log(0.5*x); const double term2 = lg.val; const double ln_pre = term1 - term2; const double ln_pre_err = GSL_DBL_EPSILON * (fabs(term1)+fabs(term2)) + lg.err; const int stat_ex = gsl_sf_exp_err_e(ln_pre, ln_pre_err, &prefactor); stat_pre = GSL_ERROR_SELECT_2(stat_ex, stat_lg); } /* Evaluate the sum. * [Abramowitz+Stegun, 9.1.10] * [Abramowitz+Stegun, 9.6.7] */ { const double y = sign * 0.25 * x*x; double sumk = 1.0; double term = 1.0; int k; for(k=1; k<=kmax; k++) { term *= y/((nu+k)*k); sumk += term; if(fabs(term/sumk) < threshold) break; } sum.val = sumk; sum.err = threshold * fabs(sumk); stat_sum = ( k >= kmax ? GSL_EMAXITER : GSL_SUCCESS ); } stat_mul = gsl_sf_multiply_err_e(prefactor.val, prefactor.err, sum.val, sum.err, result); return GSL_ERROR_SELECT_3(stat_mul, stat_pre, stat_sum); } }
/* series of hypergeometric functions for integer j > 0, x > 0 * [Goano (7)] */ static int fd_UMseries_int(const int j, const double x, gsl_sf_result * result) { const int nmax = 2000; double pre; double lnpre_val; double lnpre_err; double sum_even_val = 1.0; double sum_even_err = 0.0; double sum_odd_val = 0.0; double sum_odd_err = 0.0; int stat_sum; int stat_e; int stat_h = GSL_SUCCESS; int n; if(x < 500.0 && j < 80) { double p = gsl_sf_pow_int(x, j+1); gsl_sf_result g; gsl_sf_fact_e(j+1, &g); /* Gamma(j+2) */ lnpre_val = 0.0; lnpre_err = 0.0; pre = p/g.val; } else { double lnx = log(x); gsl_sf_result lg; gsl_sf_lngamma_e(j + 2.0, &lg); lnpre_val = (j+1.0)*lnx - lg.val; lnpre_err = 2.0 * GSL_DBL_EPSILON * fabs((j+1.0)*lnx) + lg.err; pre = 1.0; } /* Add up the odd terms of the sum. */ for(n=1; n<nmax; n+=2) { double del_val; double del_err; gsl_sf_result U; gsl_sf_result M; int stat_h_U = gsl_sf_hyperg_U_int_e(1, j+2, n*x, &U); int stat_h_F = gsl_sf_hyperg_1F1_int_e(1, j+2, -n*x, &M); stat_h = GSL_ERROR_SELECT_3(stat_h, stat_h_U, stat_h_F); del_val = ((j+1.0)*U.val - M.val); del_err = (fabs(j+1.0)*U.err + M.err); sum_odd_val += del_val; sum_odd_err += del_err; if(fabs(del_val/sum_odd_val) < GSL_DBL_EPSILON) break; } /* Add up the even terms of the sum. */ for(n=2; n<nmax; n+=2) { double del_val; double del_err; gsl_sf_result U; gsl_sf_result M; int stat_h_U = gsl_sf_hyperg_U_int_e(1, j+2, n*x, &U); int stat_h_F = gsl_sf_hyperg_1F1_int_e(1, j+2, -n*x, &M); stat_h = GSL_ERROR_SELECT_3(stat_h, stat_h_U, stat_h_F); del_val = ((j+1.0)*U.val - M.val); del_err = (fabs(j+1.0)*U.err + M.err); sum_even_val -= del_val; sum_even_err += del_err; if(fabs(del_val/sum_even_val) < GSL_DBL_EPSILON) break; } stat_sum = ( n >= nmax ? GSL_EMAXITER : GSL_SUCCESS ); stat_e = gsl_sf_exp_mult_err_e(lnpre_val, lnpre_err, pre*(sum_even_val + sum_odd_val), pre*(sum_even_err + sum_odd_err), result); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_ERROR_SELECT_3(stat_e, stat_h, stat_sum); }
/* Assumes a>0 and a+x>0. */ static int lnpoch_pos(const double a, const double x, gsl_sf_result * result) { double absx = fabs(x); if(absx > 0.1*a || absx*log(GSL_MAX_DBL(a,2.0)) > 0.1) { if(a < GSL_SF_GAMMA_XMAX && a+x < GSL_SF_GAMMA_XMAX) { /* If we can do it by calculating the gamma functions * directly, then that will be more accurate than * doing the subtraction of the logs. */ gsl_sf_result g1; gsl_sf_result g2; gsl_sf_gammainv_e(a, &g1); gsl_sf_gammainv_e(a+x, &g2); result->val = -log(g2.val/g1.val); result->err = g1.err/fabs(g1.val) + g2.err/fabs(g2.val); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } else { /* Otherwise we must do the subtraction. */ gsl_sf_result lg1; gsl_sf_result lg2; int stat_1 = gsl_sf_lngamma_e(a, &lg1); int stat_2 = gsl_sf_lngamma_e(a+x, &lg2); result->val = lg2.val - lg1.val; result->err = lg2.err + lg1.err; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_ERROR_SELECT_2(stat_1, stat_2); } } else if(absx < 0.1*a && a > 15.0) { /* Be careful about the implied subtraction. * Note that both a+x and and a must be * large here since a is not small * and x is not relatively large. * So we calculate using Stirling for Log[Gamma(z)]. * * Log[Gamma(a+x)/Gamma(a)] = x(Log[a]-1) + (x+a-1/2)Log[1+x/a] * + (1/(1+eps) - 1) / (12 a) * - (1/(1+eps)^3 - 1) / (360 a^3) * + (1/(1+eps)^5 - 1) / (1260 a^5) * - (1/(1+eps)^7 - 1) / (1680 a^7) * + ... */ const double eps = x/a; const double den = 1.0 + eps; const double d3 = den*den*den; const double d5 = d3*den*den; const double d7 = d5*den*den; const double c1 = -eps/den; const double c3 = -eps*(3.0+eps*(3.0+eps))/d3; const double c5 = -eps*(5.0+eps*(10.0+eps*(10.0+eps*(5.0+eps))))/d5; const double c7 = -eps*(7.0+eps*(21.0+eps*(35.0+eps*(35.0+eps*(21.0+eps*(7.0+eps))))))/d7; const double p8 = gsl_sf_pow_int(1.0+eps,8); const double c8 = 1.0/p8 - 1.0; /* these need not */ const double c9 = 1.0/(p8*(1.0+eps)) - 1.0; /* be very accurate */ const double a4 = a*a*a*a; const double a6 = a4*a*a; const double ser_1 = c1 + c3/(30.0*a*a) + c5/(105.0*a4) + c7/(140.0*a6); const double ser_2 = c8/(99.0*a6*a*a) - 691.0/360360.0 * c9/(a6*a4); const double ser = (ser_1 + ser_2)/ (12.0*a); double term1 = x * log(a/M_E); double term2; gsl_sf_result ln_1peps; gsl_sf_log_1plusx_e(eps, &ln_1peps); /* log(1 + x/a) */ term2 = (x + a - 0.5) * ln_1peps.val; result->val = term1 + term2 + ser; result->err = GSL_DBL_EPSILON*fabs(term1); result->err += fabs((x + a - 0.5)*ln_1peps.err); result->err += fabs(ln_1peps.val) * GSL_DBL_EPSILON * (fabs(x) + fabs(a) + 0.5); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } else { gsl_sf_result poch_rel; int stat_p = pochrel_smallx(a, x, &poch_rel); double eps = x*poch_rel.val; int stat_e = gsl_sf_log_1plusx_e(eps, result); result->err = 2.0 * fabs(x * poch_rel.err / (1.0 + eps)); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_ERROR_SELECT_2(stat_e, stat_p); } }
int gsl_sf_hyperg_U_large_b_e(const double a, const double b, const double x, gsl_sf_result * result, double * ln_multiplier ) { double N = floor(b); /* b = N + eps */ double eps = b - N; if(fabs(eps) < GSL_SQRT_DBL_EPSILON) { double lnpre_val; double lnpre_err; gsl_sf_result M; if(b > 1.0) { double tmp = (1.0-b)*log(x); gsl_sf_result lg_bm1; gsl_sf_result lg_a; gsl_sf_lngamma_e(b-1.0, &lg_bm1); gsl_sf_lngamma_e(a, &lg_a); lnpre_val = tmp + x + lg_bm1.val - lg_a.val; lnpre_err = lg_bm1.err + lg_a.err + GSL_DBL_EPSILON * (fabs(x) + fabs(tmp)); gsl_sf_hyperg_1F1_large_b_e(1.0-a, 2.0-b, -x, &M); } else { gsl_sf_result lg_1mb; gsl_sf_result lg_1pamb; gsl_sf_lngamma_e(1.0-b, &lg_1mb); gsl_sf_lngamma_e(1.0+a-b, &lg_1pamb); lnpre_val = lg_1mb.val - lg_1pamb.val; lnpre_err = lg_1mb.err + lg_1pamb.err; gsl_sf_hyperg_1F1_large_b_e(a, b, x, &M); } if(lnpre_val > GSL_LOG_DBL_MAX-10.0) { result->val = M.val; result->err = M.err; *ln_multiplier = lnpre_val; GSL_ERROR ("overflow", GSL_EOVRFLW); } else { gsl_sf_result epre; int stat_e = gsl_sf_exp_err_e(lnpre_val, lnpre_err, &epre); result->val = epre.val * M.val; result->err = epre.val * M.err + epre.err * fabs(M.val); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); *ln_multiplier = 0.0; return stat_e; } } else { double omb_lnx = (1.0-b)*log(x); gsl_sf_result lg_1mb; double sgn_1mb; gsl_sf_result lg_1pamb; double sgn_1pamb; gsl_sf_result lg_bm1; double sgn_bm1; gsl_sf_result lg_a; double sgn_a; gsl_sf_result M1, M2; double lnpre1_val, lnpre2_val; double lnpre1_err, lnpre2_err; double sgpre1, sgpre2; gsl_sf_hyperg_1F1_large_b_e( a, b, x, &M1); gsl_sf_hyperg_1F1_large_b_e(1.0-a, 2.0-b, x, &M2); gsl_sf_lngamma_sgn_e(1.0-b, &lg_1mb, &sgn_1mb); gsl_sf_lngamma_sgn_e(1.0+a-b, &lg_1pamb, &sgn_1pamb); gsl_sf_lngamma_sgn_e(b-1.0, &lg_bm1, &sgn_bm1); gsl_sf_lngamma_sgn_e(a, &lg_a, &sgn_a); lnpre1_val = lg_1mb.val - lg_1pamb.val; lnpre1_err = lg_1mb.err + lg_1pamb.err; lnpre2_val = lg_bm1.val - lg_a.val - omb_lnx - x; lnpre2_err = lg_bm1.err + lg_a.err + GSL_DBL_EPSILON * (fabs(omb_lnx)+fabs(x)); sgpre1 = sgn_1mb * sgn_1pamb; sgpre2 = sgn_bm1 * sgn_a; if(lnpre1_val > GSL_LOG_DBL_MAX-10.0 || lnpre2_val > GSL_LOG_DBL_MAX-10.0) { double max_lnpre_val = GSL_MAX(lnpre1_val,lnpre2_val); double max_lnpre_err = GSL_MAX(lnpre1_err,lnpre2_err); double lp1 = lnpre1_val - max_lnpre_val; double lp2 = lnpre2_val - max_lnpre_val; double t1 = sgpre1*exp(lp1); double t2 = sgpre2*exp(lp2); result->val = t1*M1.val + t2*M2.val; result->err = fabs(t1)*M1.err + fabs(t2)*M2.err; result->err += GSL_DBL_EPSILON * exp(max_lnpre_err) * (fabs(t1*M1.val) + fabs(t2*M2.val)); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); *ln_multiplier = max_lnpre_val; GSL_ERROR ("overflow", GSL_EOVRFLW); } else { double t1 = sgpre1*exp(lnpre1_val); double t2 = sgpre2*exp(lnpre2_val); result->val = t1*M1.val + t2*M2.val; result->err = fabs(t1) * M1.err + fabs(t2)*M2.err; result->err += GSL_DBL_EPSILON * (exp(lnpre1_err)*fabs(t1*M1.val) + exp(lnpre2_err)*fabs(t2*M2.val)); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); *ln_multiplier = 0.0; return GSL_SUCCESS; } } }
int gsl_sf_hyperg_2F1_e(double a, double b, const double c, const double x, gsl_sf_result * result) { const double d = c - a - b; const double rinta = floor(a + 0.5); const double rintb = floor(b + 0.5); const double rintc = floor(c + 0.5); const int a_neg_integer = ( a < 0.0 && fabs(a - rinta) < locEPS ); const int b_neg_integer = ( b < 0.0 && fabs(b - rintb) < locEPS ); const int c_neg_integer = ( c < 0.0 && fabs(c - rintc) < locEPS ); result->val = 0.0; result->err = 0.0; /* Handle x == 1.0 RJM */ if (fabs (x - 1.0) < locEPS && (c - a - b) > 0 && c != 0 && !c_neg_integer) { gsl_sf_result lngamc, lngamcab, lngamca, lngamcb; double lngamc_sgn, lngamca_sgn, lngamcb_sgn; int status; int stat1 = gsl_sf_lngamma_sgn_e (c, &lngamc, &lngamc_sgn); int stat2 = gsl_sf_lngamma_e (c - a - b, &lngamcab); int stat3 = gsl_sf_lngamma_sgn_e (c - a, &lngamca, &lngamca_sgn); int stat4 = gsl_sf_lngamma_sgn_e (c - b, &lngamcb, &lngamcb_sgn); if (stat1 != GSL_SUCCESS || stat2 != GSL_SUCCESS || stat3 != GSL_SUCCESS || stat4 != GSL_SUCCESS) { DOMAIN_ERROR (result); } status = gsl_sf_exp_err_e (lngamc.val + lngamcab.val - lngamca.val - lngamcb.val, lngamc.err + lngamcab.err + lngamca.err + lngamcb.err, result); result->val *= lngamc_sgn / (lngamca_sgn * lngamcb_sgn); return status; } if(x < -1.0 || 1.0 <= x) { DOMAIN_ERROR(result); } if(c_neg_integer) { /* If c is a negative integer, then either a or b must be a negative integer of smaller magnitude than c to ensure cancellation of the series. */ if(! (a_neg_integer && a > c + 0.1) && ! (b_neg_integer && b > c + 0.1)) { DOMAIN_ERROR(result); } } if(fabs(c-b) < locEPS || fabs(c-a) < locEPS) { return pow_omx(x, d, result); /* (1-x)^(c-a-b) */ } if(a >= 0.0 && b >= 0.0 && c >=0.0 && x >= 0.0 && x < 0.995) { /* Series has all positive definite * terms and x is not close to 1. */ return hyperg_2F1_series(a, b, c, x, result); } if(fabs(a) < 10.0 && fabs(b) < 10.0) { /* a and b are not too large, so we attempt * variations on the series summation. */ if(a_neg_integer) { return hyperg_2F1_series(rinta, b, c, x, result); } if(b_neg_integer) { return hyperg_2F1_series(a, rintb, c, x, result); } if(x < -0.25) { return hyperg_2F1_luke(a, b, c, x, result); } else if(x < 0.5) { return hyperg_2F1_series(a, b, c, x, result); } else { if(fabs(c) > 10.0) { return hyperg_2F1_series(a, b, c, x, result); } else { return hyperg_2F1_reflect(a, b, c, x, result); } } } else { /* Either a or b or both large. * Introduce some new variables ap,bp so that bp is * the larger in magnitude. */ double ap, bp; if(fabs(a) > fabs(b)) { bp = a; ap = b; } else { bp = b; ap = a; } if(x < 0.0) { /* What the hell, maybe Luke will converge. */ return hyperg_2F1_luke(a, b, c, x, result); } if(GSL_MAX_DBL(fabs(a),1.0)*fabs(bp)*fabs(x) < 2.0*fabs(c)) { /* If c is large enough or x is small enough, * we can attempt the series anyway. */ return hyperg_2F1_series(a, b, c, x, result); } if(fabs(bp*bp*x*x) < 0.001*fabs(bp) && fabs(a) < 10.0) { /* The famous but nearly worthless "large b" asymptotic. */ int stat = gsl_sf_hyperg_1F1_e(a, c, bp*x, result); result->err = 0.001 * fabs(result->val); return stat; } /* We give up. */ result->val = 0.0; result->err = 0.0; GSL_ERROR ("error", GSL_EUNIMPL); } }
/* Do the reflection described in [Moshier, p. 334]. * Assumes a,b,c != neg integer. */ static int hyperg_2F1_reflect(const double a, const double b, const double c, const double x, gsl_sf_result * result) { const double d = c - a - b; const int intd = floor(d+0.5); const int d_integer = ( fabs(d - intd) < locEPS ); if(d_integer) { const double ln_omx = log(1.0 - x); const double ad = fabs(d); int stat_F2 = GSL_SUCCESS; double sgn_2; gsl_sf_result F1; gsl_sf_result F2; double d1, d2; gsl_sf_result lng_c; gsl_sf_result lng_ad2; gsl_sf_result lng_bd2; int stat_c; int stat_ad2; int stat_bd2; if(d >= 0.0) { d1 = d; d2 = 0.0; } else { d1 = 0.0; d2 = d; } stat_ad2 = gsl_sf_lngamma_e(a+d2, &lng_ad2); stat_bd2 = gsl_sf_lngamma_e(b+d2, &lng_bd2); stat_c = gsl_sf_lngamma_e(c, &lng_c); /* Evaluate F1. */ if(ad < GSL_DBL_EPSILON) { /* d = 0 */ F1.val = 0.0; F1.err = 0.0; } else { gsl_sf_result lng_ad; gsl_sf_result lng_ad1; gsl_sf_result lng_bd1; int stat_ad = gsl_sf_lngamma_e(ad, &lng_ad); int stat_ad1 = gsl_sf_lngamma_e(a+d1, &lng_ad1); int stat_bd1 = gsl_sf_lngamma_e(b+d1, &lng_bd1); if(stat_ad1 == GSL_SUCCESS && stat_bd1 == GSL_SUCCESS && stat_ad == GSL_SUCCESS) { /* Gamma functions in the denominator are ok. * Proceed with evaluation. */ int i; double sum1 = 1.0; double term = 1.0; double ln_pre1_val = lng_ad.val + lng_c.val + d2*ln_omx - lng_ad1.val - lng_bd1.val; double ln_pre1_err = lng_ad.err + lng_c.err + lng_ad1.err + lng_bd1.err + GSL_DBL_EPSILON * fabs(ln_pre1_val); int stat_e; /* Do F1 sum. */ for(i=1; i<ad; i++) { int j = i-1; term *= (a + d2 + j) * (b + d2 + j) / (1.0 + d2 + j) / i * (1.0-x); sum1 += term; } stat_e = gsl_sf_exp_mult_err_e(ln_pre1_val, ln_pre1_err, sum1, GSL_DBL_EPSILON*fabs(sum1), &F1); if(stat_e == GSL_EOVRFLW) { OVERFLOW_ERROR(result); } } else { /* Gamma functions in the denominator were not ok. * So the F1 term is zero. */ F1.val = 0.0; F1.err = 0.0; } } /* end F1 evaluation */ /* Evaluate F2. */ if(stat_ad2 == GSL_SUCCESS && stat_bd2 == GSL_SUCCESS) { /* Gamma functions in the denominator are ok. * Proceed with evaluation. */ const int maxiter = 2000; double psi_1 = -M_EULER; gsl_sf_result psi_1pd; gsl_sf_result psi_apd1; gsl_sf_result psi_bpd1; int stat_1pd = gsl_sf_psi_e(1.0 + ad, &psi_1pd); int stat_apd1 = gsl_sf_psi_e(a + d1, &psi_apd1); int stat_bpd1 = gsl_sf_psi_e(b + d1, &psi_bpd1); int stat_dall = GSL_ERROR_SELECT_3(stat_1pd, stat_apd1, stat_bpd1); double psi_val = psi_1 + psi_1pd.val - psi_apd1.val - psi_bpd1.val - ln_omx; double psi_err = psi_1pd.err + psi_apd1.err + psi_bpd1.err + GSL_DBL_EPSILON*fabs(psi_val); double fact = 1.0; double sum2_val = psi_val; double sum2_err = psi_err; double ln_pre2_val = lng_c.val + d1*ln_omx - lng_ad2.val - lng_bd2.val; double ln_pre2_err = lng_c.err + lng_ad2.err + lng_bd2.err + GSL_DBL_EPSILON * fabs(ln_pre2_val); int stat_e; int j; /* Do F2 sum. */ for(j=1; j<maxiter; j++) { /* values for psi functions use recurrence; Abramowitz+Stegun 6.3.5 */ double term1 = 1.0/(double)j + 1.0/(ad+j); double term2 = 1.0/(a+d1+j-1.0) + 1.0/(b+d1+j-1.0); double delta = 0.0; psi_val += term1 - term2; psi_err += GSL_DBL_EPSILON * (fabs(term1) + fabs(term2)); fact *= (a+d1+j-1.0)*(b+d1+j-1.0)/((ad+j)*j) * (1.0-x); delta = fact * psi_val; sum2_val += delta; sum2_err += fabs(fact * psi_err) + GSL_DBL_EPSILON*fabs(delta); if(fabs(delta) < GSL_DBL_EPSILON * fabs(sum2_val)) break; } if(j == maxiter) stat_F2 = GSL_EMAXITER; if(sum2_val == 0.0) { F2.val = 0.0; F2.err = 0.0; } else { stat_e = gsl_sf_exp_mult_err_e(ln_pre2_val, ln_pre2_err, sum2_val, sum2_err, &F2); if(stat_e == GSL_EOVRFLW) { result->val = 0.0; result->err = 0.0; GSL_ERROR ("error", GSL_EOVRFLW); } } stat_F2 = GSL_ERROR_SELECT_2(stat_F2, stat_dall); } else { /* Gamma functions in the denominator not ok. * So the F2 term is zero. */ F2.val = 0.0; F2.err = 0.0; } /* end F2 evaluation */ sgn_2 = ( GSL_IS_ODD(intd) ? -1.0 : 1.0 ); result->val = F1.val + sgn_2 * F2.val; result->err = F1.err + F2. err; result->err += 2.0 * GSL_DBL_EPSILON * (fabs(F1.val) + fabs(F2.val)); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return stat_F2; } else { /* d not an integer */ gsl_sf_result pre1, pre2; double sgn1, sgn2; gsl_sf_result F1, F2; int status_F1, status_F2; /* These gamma functions appear in the denominator, so we * catch their harmless domain errors and set the terms to zero. */ gsl_sf_result ln_g1ca, ln_g1cb, ln_g2a, ln_g2b; double sgn_g1ca, sgn_g1cb, sgn_g2a, sgn_g2b; int stat_1ca = gsl_sf_lngamma_sgn_e(c-a, &ln_g1ca, &sgn_g1ca); int stat_1cb = gsl_sf_lngamma_sgn_e(c-b, &ln_g1cb, &sgn_g1cb); int stat_2a = gsl_sf_lngamma_sgn_e(a, &ln_g2a, &sgn_g2a); int stat_2b = gsl_sf_lngamma_sgn_e(b, &ln_g2b, &sgn_g2b); int ok1 = (stat_1ca == GSL_SUCCESS && stat_1cb == GSL_SUCCESS); int ok2 = (stat_2a == GSL_SUCCESS && stat_2b == GSL_SUCCESS); gsl_sf_result ln_gc, ln_gd, ln_gmd; double sgn_gc, sgn_gd, sgn_gmd; gsl_sf_lngamma_sgn_e( c, &ln_gc, &sgn_gc); gsl_sf_lngamma_sgn_e( d, &ln_gd, &sgn_gd); gsl_sf_lngamma_sgn_e(-d, &ln_gmd, &sgn_gmd); sgn1 = sgn_gc * sgn_gd * sgn_g1ca * sgn_g1cb; sgn2 = sgn_gc * sgn_gmd * sgn_g2a * sgn_g2b; if(ok1 && ok2) { double ln_pre1_val = ln_gc.val + ln_gd.val - ln_g1ca.val - ln_g1cb.val; double ln_pre2_val = ln_gc.val + ln_gmd.val - ln_g2a.val - ln_g2b.val + d*log(1.0-x); double ln_pre1_err = ln_gc.err + ln_gd.err + ln_g1ca.err + ln_g1cb.err; double ln_pre2_err = ln_gc.err + ln_gmd.err + ln_g2a.err + ln_g2b.err; if(ln_pre1_val < GSL_LOG_DBL_MAX && ln_pre2_val < GSL_LOG_DBL_MAX) { gsl_sf_exp_err_e(ln_pre1_val, ln_pre1_err, &pre1); gsl_sf_exp_err_e(ln_pre2_val, ln_pre2_err, &pre2); pre1.val *= sgn1; pre2.val *= sgn2; } else { OVERFLOW_ERROR(result); } } else if(ok1 && !ok2) { double ln_pre1_val = ln_gc.val + ln_gd.val - ln_g1ca.val - ln_g1cb.val; double ln_pre1_err = ln_gc.err + ln_gd.err + ln_g1ca.err + ln_g1cb.err; if(ln_pre1_val < GSL_LOG_DBL_MAX) { gsl_sf_exp_err_e(ln_pre1_val, ln_pre1_err, &pre1); pre1.val *= sgn1; pre2.val = 0.0; pre2.err = 0.0; } else { OVERFLOW_ERROR(result); } } else if(!ok1 && ok2) { double ln_pre2_val = ln_gc.val + ln_gmd.val - ln_g2a.val - ln_g2b.val + d*log(1.0-x); double ln_pre2_err = ln_gc.err + ln_gmd.err + ln_g2a.err + ln_g2b.err; if(ln_pre2_val < GSL_LOG_DBL_MAX) { pre1.val = 0.0; pre1.err = 0.0; gsl_sf_exp_err_e(ln_pre2_val, ln_pre2_err, &pre2); pre2.val *= sgn2; } else { OVERFLOW_ERROR(result); } } else { pre1.val = 0.0; pre2.val = 0.0; UNDERFLOW_ERROR(result); } status_F1 = hyperg_2F1_series( a, b, 1.0-d, 1.0-x, &F1); status_F2 = hyperg_2F1_series(c-a, c-b, 1.0+d, 1.0-x, &F2); result->val = pre1.val*F1.val + pre2.val*F2.val; result->err = fabs(pre1.val*F1.err) + fabs(pre2.val*F2.err); result->err += fabs(pre1.err*F1.val) + fabs(pre2.err*F2.val); result->err += 2.0 * GSL_DBL_EPSILON * (fabs(pre1.val*F1.val) + fabs(pre2.val*F2.val)); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_SUCCESS; } }