gamma_inc.c

来自「math library from gnu」· C语言 代码 · 共 722 行 · 第 1/2 页

C
722
字号
                       * (-1.28459889470864700 + lnx)                       * (-0.27583535756454143 + lnx)                       * ( 1.33677371336239618 + lnx)                       * ( 5.17537282427561550 + lnx);    const double c6 = -0.0013888888888888889                       * (-2.30814336454783200 + lnx)                       * (-1.65846557706987300 + lnx)                       * (-0.88768082560020400 + lnx)                       * ( 0.17043847751371778 + lnx)                       * ( 1.92135970115863890 + lnx)                       * ( 6.22578557795474900 + lnx);    const double c7 = -0.00019841269841269841                       * (-2.5078657901291800 + lnx)                       * (-1.9478900888958200 + lnx)                       * (-1.3194837322612730 + lnx)                       * (-0.5281322700249279 + lnx)                       * ( 0.5913834939078759 + lnx)                       * ( 2.4876819633378140 + lnx)                       * ( 7.2648160783762400 + lnx);    const double c8 = -0.00002480158730158730                       * (-2.677341544966400 + lnx)                       * (-2.182810448271700 + lnx)                       * (-1.649350342277400 + lnx)                       * (-1.014099048290790 + lnx)                       * (-0.191366955370652 + lnx)                       * ( 0.995403817918724 + lnx)                       * ( 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 double am1lgx = (a-1.0)*log(x);  const int stat_F = gamma_inc_F_CF(a, x, &F);  const int stat_E = gsl_sf_exp_err_e(am1lgx - x, GSL_DBL_EPSILON*fabs(am1lgx), &pre);  result->val = F.val * pre.val;  result->err = fabs(F.err * pre.val) + fabs(F.val * pre.err);  result->err += 2.0 * 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(x > a - sqrt(a)) {      /* 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 + =
减小字号Ctrl + -
显示快捷键?