📄 gamma_inc.c
字号:
* ( 3.041323283529310 + lnx) * ( 8.295966556941250 + lnx); const double c9 = -2.75573192239859e-6 * (-2.8243487670469080 + lnx) * (-2.3798494322701120 + lnx) * (-1.9143674728689960 + lnx) * (-1.3814529102920370 + lnx) * (-0.7294312810261694 + lnx) * ( 0.1299079285269565 + lnx) * ( 1.3873333251885240 + lnx) * ( 3.5857258865210760 + lnx) * ( 9.3214237073814600 + lnx); const double c10 = -2.75573192239859e-7 * (-2.9540329644556910 + lnx) * (-2.5491366926991850 + lnx) * (-2.1348279229279880 + lnx) * (-1.6741881076349450 + lnx) * (-1.1325949616098420 + lnx) * (-0.4590034650618494 + lnx) * ( 0.4399352987435699 + lnx) * ( 1.7702236517651670 + lnx) * ( 4.1231539047474080 + lnx) * ( 10.342627908148680 + lnx); term1 = a*(c1+a*(c2+a*(c3+a*(c4+a*(c5+a*(c6+a*(c7+a*(c8+a*(c9+a*c10))))))))); } { /* Evaluate the sum. */ const int nmax = 5000; double t = 1.0; int n; sum = 1.0; for(n=1; n<nmax; n++) { t *= -x/(n+1.0); sum += (a+1.0)/(a+n+1.0)*t; if(fabs(t/sum) < GSL_DBL_EPSILON) break; } if(n == nmax) stat_sum = GSL_EMAXITER; else stat_sum = GSL_SUCCESS; } term2 = (1.0 - term1) * a/(a+1.0) * x * sum; result->val = term1 + term2; result->err = GSL_DBL_EPSILON * (fabs(term1) + 2.0*fabs(term2)); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return stat_sum;}/* series for small a and x, but not defined for a == 0 */static intgamma_inc_series(double a, double x, gsl_sf_result * result){ gsl_sf_result Q; gsl_sf_result G; const int stat_Q = gamma_inc_Q_series(a, x, &Q); const int stat_G = gsl_sf_gamma_e(a, &G); result->val = Q.val * G.val; result->err = fabs(Q.val * G.err) + fabs(Q.err * G.val); result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return GSL_ERROR_SELECT_2(stat_Q, stat_G);}static intgamma_inc_a_gt_0(double a, double x, gsl_sf_result * result){ /* x > 0 and a > 0; use result for Q */ gsl_sf_result Q; gsl_sf_result G; const int stat_Q = gsl_sf_gamma_inc_Q_e(a, x, &Q); const int stat_G = gsl_sf_gamma_e(a, &G); result->val = G.val * Q.val; result->err = fabs(G.val * Q.err) + fabs(G.err * Q.val); result->err += 2.0*GSL_DBL_EPSILON * fabs(result->val); return GSL_ERROR_SELECT_2(stat_G, stat_Q);}static intgamma_inc_CF(double a, double x, gsl_sf_result * result){ gsl_sf_result F; gsl_sf_result pre; const int stat_F = gamma_inc_F_CF(a, x, &F); const int stat_E = gsl_sf_exp_e((a-1.0)*log(x) - x, &pre); result->val = F.val * pre.val; result->err = fabs(F.err * pre.val) + fabs(F.val * pre.err); result->err += (2.0 + fabs(a)) * GSL_DBL_EPSILON * fabs(result->val); return GSL_ERROR_SELECT_2(stat_F, stat_E);}/* evaluate Gamma(0,x), x > 0 */#define GAMMA_INC_A_0(x, result) gsl_sf_expint_E1_e(x, result)/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/intgsl_sf_gamma_inc_Q_e(const double a, const double x, gsl_sf_result * result){ if(a < 0.0 || x < 0.0) { DOMAIN_ERROR(result); } else if(x == 0.0) { result->val = 1.0; result->err = 0.0; return GSL_SUCCESS; } else if(a == 0.0) { result->val = 0.0; result->err = 0.0; return GSL_SUCCESS; } else if(x <= 0.5*a) { /* If the series is quick, do that. It is * robust and simple. */ gsl_sf_result P; int stat_P = gamma_inc_P_series(a, x, &P); result->val = 1.0 - P.val; result->err = P.err; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return stat_P; } else if(a >= 1.0e+06 && (x-a)*(x-a) < a) { /* Then try the difficult asymptotic regime. * This is the only way to do this region. */ return gamma_inc_Q_asymp_unif(a, x, result); } else if(a < 0.2 && x < 5.0) { /* Cancellations at small a must be handled * analytically; x should not be too big * either since the series terms grow * with x and log(x). */ return gamma_inc_Q_series(a, x, result); } else if(a <= x) { if(x <= 1.0e+06) { /* Continued fraction is excellent for x >~ a. * We do not let x be too large when x > a since * it is somewhat pointless to try this there; * the function is rapidly decreasing for * x large and x > a, and it will just * underflow in that region anyway. We * catch that case in the standard * large-x method. */ return gamma_inc_Q_CF(a, x, result); } else { return gamma_inc_Q_large_x(a, x, result); } } else { if(a < 0.8*x) { /* Continued fraction again. The convergence * is a little slower here, but that is fine. * We have to trade that off against the slow * convergence of the series, which is the * only other option. */ return gamma_inc_Q_CF(a, x, result); } else { gsl_sf_result P; int stat_P = gamma_inc_P_series(a, x, &P); result->val = 1.0 - P.val; result->err = P.err; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return stat_P; } }}intgsl_sf_gamma_inc_P_e(const double a, const double x, gsl_sf_result * result){ if(a <= 0.0 || x < 0.0) { DOMAIN_ERROR(result); } else if(x == 0.0) { result->val = 0.0; result->err = 0.0; return GSL_SUCCESS; } else if(x < 20.0 || x < 0.5*a) { /* Do the easy series cases. Robust and quick. */ return gamma_inc_P_series(a, x, result); } else if(a > 1.0e+06 && (x-a)*(x-a) < a) { /* Crossover region. Note that Q and P are * roughly the same order of magnitude here, * so the subtraction is stable. */ gsl_sf_result Q; int stat_Q = gamma_inc_Q_asymp_unif(a, x, &Q); result->val = 1.0 - Q.val; result->err = Q.err; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return stat_Q; } else if(a <= x) { /* Q <~ P in this area, so the * subtractions are stable. */ gsl_sf_result Q; int stat_Q; if(a > 0.2*x) { stat_Q = gamma_inc_Q_CF(a, x, &Q); } else { stat_Q = gamma_inc_Q_large_x(a, x, &Q); } result->val = 1.0 - Q.val; result->err = Q.err; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return stat_Q; } else { if((x-a)*(x-a) < a) { /* This condition is meant to insure * that Q is not very close to 1, * so the subtraction is stable. */ gsl_sf_result Q; int stat_Q = gamma_inc_Q_CF(a, x, &Q); result->val = 1.0 - Q.val; result->err = Q.err; result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val); return stat_Q; } else { return gamma_inc_P_series(a, x, result); } }}intgsl_sf_gamma_inc_e(const double a, const double x, gsl_sf_result * result){ if(x < 0.0) { DOMAIN_ERROR(result); } else if(x == 0.0) { return gsl_sf_gamma_e(a, result); } else if(a == 0.0) { return GAMMA_INC_A_0(x, result); } else if(a > 0.0) { return gamma_inc_a_gt_0(a, x, result); } else if(x > 0.25) { /* continued fraction seems to fail for x too small; otherwise it is ok, independent of the value of |x/a|, because of the non-oscillation in the expansion, i.e. the CF is un-conditionally convergent for a < 0 and x > 0 */ return gamma_inc_CF(a, x, result); } else if(fabs(a) < 0.5) { return gamma_inc_series(a, x, result); } else { /* a = fa + da; da >= 0 */ const double fa = floor(a); const double da = a - fa; gsl_sf_result g_da; const int stat_g_da = ( da > 0.0 ? gamma_inc_a_gt_0(da, x, &g_da) : GAMMA_INC_A_0(x, &g_da)); double alpha = da; double gax = g_da.val; /* Gamma(alpha-1,x) = 1/(alpha-1) (Gamma(a,x) - x^(alpha-1) e^-x) */ do { const double shift = exp(-x + (alpha-1.0)*log(x)); gax = (gax - shift) / (alpha - 1.0); alpha -= 1.0; } while(alpha > a); result->val = gax; result->err = 2.0*(1.0 + fabs(a))*GSL_DBL_EPSILON*fabs(gax); return stat_g_da; }}/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/#include "eval.h"double gsl_sf_gamma_inc_P(const double a, const double x){ EVAL_RESULT(gsl_sf_gamma_inc_P_e(a, x, &result));}double gsl_sf_gamma_inc_Q(const double a, const double x){ EVAL_RESULT(gsl_sf_gamma_inc_Q_e(a, x, &result));}double gsl_sf_gamma_inc(const double a, const double x){ EVAL_RESULT(gsl_sf_gamma_inc_e(a, x, &result));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -