⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hyperg_1f1.c

📁 开放gsl矩阵运算
💻 C
📖 第 1 页 / 共 4 页
字号:
 */staticinthyperg_1F1_CF1_p_ser(const double a, const double b, const double x, double * result){  if(a == 0.0) {    *result = 0.0;    return GSL_SUCCESS;  }  else {    const int maxiter = 5000;    double sum  = 1.0;    double pk   = 1.0;    double rhok = 0.0;    int k;    for(k=1; k<maxiter; k++) {      double ak = (a + k)*x/((b-x+k-1.0)*(b-x+k));      rhok = -ak*(1.0 + rhok)/(1.0 + ak*(1.0+rhok));      pk  *= rhok;      sum += pk;      if(fabs(pk/sum) < 2.0*GSL_DBL_EPSILON) break;    }    *result = a/(b-x) * sum;    if(k == maxiter)      GSL_ERROR ("error", GSL_EMAXITER);    else      return GSL_SUCCESS;  }}/* 1F1(a+1,b,x)/1F1(a,b,x) * * I think this suffers from typical "anomalous convergence". * I could not find a region where it was truly useful. */#if 0staticinthyperg_1F1_CF1(const double a, const double b, const double x, double * result){  const double RECUR_BIG = GSL_SQRT_DBL_MAX;  const int maxiter = 5000;  int n = 1;  double Anm2 = 1.0;  double Bnm2 = 0.0;  double Anm1 = 0.0;  double Bnm1 = 1.0;  double a1 = b - a - 1.0;  double b1 = b - x - 2.0*(a+1.0);  double An = b1*Anm1 + a1*Anm2;  double Bn = b1*Bnm1 + a1*Bnm2;  double an, bn;  double fn = An/Bn;  while(n < maxiter) {    double old_fn;    double del;    n++;    Anm2 = Anm1;    Bnm2 = Bnm1;    Anm1 = An;    Bnm1 = Bn;    an = (a + n - 1.0) * (b - a - n);    bn = b - x - 2.0*(a+n);    An = bn*Anm1 + an*Anm2;    Bn = bn*Bnm1 + an*Bnm2;    if(fabs(An) > RECUR_BIG || fabs(Bn) > RECUR_BIG) {      An /= RECUR_BIG;      Bn /= RECUR_BIG;      Anm1 /= RECUR_BIG;      Bnm1 /= RECUR_BIG;      Anm2 /= RECUR_BIG;      Bnm2 /= RECUR_BIG;    }    old_fn = fn;    fn = An/Bn;    del = old_fn/fn;        if(fabs(del - 1.0) < 10.0*GSL_DBL_EPSILON) break;  }  *result = fn;  if(n == maxiter)    GSL_ERROR ("error", GSL_EMAXITER);  else    return GSL_SUCCESS;}#endif /* 0 *//* 1F1(a,b+1,x)/1F1(a,b,x) * * This seemed to suffer from "anomalous convergence". * However, I have no theory for this recurrence. */#if 0staticinthyperg_1F1_CF1_b(const double a, const double b, const double x, double * result){  const double RECUR_BIG = GSL_SQRT_DBL_MAX;  const int maxiter = 5000;  int n = 1;  double Anm2 = 1.0;  double Bnm2 = 0.0;  double Anm1 = 0.0;  double Bnm1 = 1.0;  double a1 = b + 1.0;  double b1 = (b + 1.0) * (b - x);  double An = b1*Anm1 + a1*Anm2;  double Bn = b1*Bnm1 + a1*Bnm2;  double an, bn;  double fn = An/Bn;  while(n < maxiter) {    double old_fn;    double del;    n++;    Anm2 = Anm1;    Bnm2 = Bnm1;    Anm1 = An;    Bnm1 = Bn;    an = (b + n) * (b + n - 1.0 - a) * x;    bn = (b + n) * (b + n - 1.0 - x);    An = bn*Anm1 + an*Anm2;    Bn = bn*Bnm1 + an*Bnm2;    if(fabs(An) > RECUR_BIG || fabs(Bn) > RECUR_BIG) {      An /= RECUR_BIG;      Bn /= RECUR_BIG;      Anm1 /= RECUR_BIG;      Bnm1 /= RECUR_BIG;      Anm2 /= RECUR_BIG;      Bnm2 /= RECUR_BIG;    }    old_fn = fn;    fn = An/Bn;    del = old_fn/fn;        if(fabs(del - 1.0) < 10.0*GSL_DBL_EPSILON) break;  }  *result = fn;  if(n == maxiter)    GSL_ERROR ("error", GSL_EMAXITER);  else    return GSL_SUCCESS;}#endif /* 0 *//* 1F1(a,b,x) * |a| <= 1, b > 0 */staticinthyperg_1F1_small_a_bgt0(const double a, const double b, const double x, gsl_sf_result * result){  const double bma = b-a;  const double oma = 1.0-a;  const double ap1mb = 1.0+a-b;  const double abs_bma = fabs(bma);  const double abs_oma = fabs(oma);  const double abs_ap1mb = fabs(ap1mb);  const double ax = fabs(x);  if(a == 0.0) {    result->val = 1.0;    result->err = 0.0;    return GSL_SUCCESS;  }  else if(a == 1.0) {    return hyperg_1F1_1(b, x, result);  }  else if(a == -1.0) {    result->val  = 1.0 + a/b * x;    result->err  = GSL_DBL_EPSILON * (1.0 + fabs(a/b * x));    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);    return GSL_SUCCESS;  }  else if(b >= 1.4*ax) {    return gsl_sf_hyperg_1F1_series_e(a, b, x, result);  }  else if(x > 0.0) {    if(x > 100.0 && abs_bma*abs_oma < 0.5*x) {      return hyperg_1F1_asymp_posx(a, b, x, result);    }    else if(b < 5.0e+06) {      /* Recurse backward on b from       * a suitably high point.       */      const double b_del = ceil(1.4*x-b) + 1.0;      double bp = b + b_del;      gsl_sf_result r_Mbp1;      gsl_sf_result r_Mb;      double Mbp1;      double Mb;      double Mbm1;      int stat_0 = gsl_sf_hyperg_1F1_series_e(a, bp+1.0, x, &r_Mbp1);      int stat_1 = gsl_sf_hyperg_1F1_series_e(a, bp,     x, &r_Mb);      const double err_rat = fabs(r_Mbp1.err/r_Mbp1.val) + fabs(r_Mb.err/r_Mb.val);      Mbp1 = r_Mbp1.val;      Mb   = r_Mb.val;      while(bp > b+0.1) {        /* Do backward recursion. */        Mbm1 = ((x+bp-1.0)*Mb - x*(bp-a)/bp*Mbp1)/(bp-1.0);        bp -= 1.0;	Mbp1 = Mb;	Mb   = Mbm1;      }      result->val  = Mb;      result->err  = err_rat * (fabs(b_del)+1.0) * fabs(Mb);      result->err += 2.0 * GSL_DBL_EPSILON * fabs(Mb);      return GSL_ERROR_SELECT_2(stat_0, stat_1);    }    else {      return hyperg_1F1_large2bm4a(a, b, x, result);    }  }  else {    /* x < 0 and b not large compared to |x|     */    if(ax < 10.0 && b < 10.0) {      return gsl_sf_hyperg_1F1_series_e(a, b, x, result);    }    else if(ax >= 100.0 && GSL_MAX(abs_ap1mb,1.0) < 0.99*ax) {      return hyperg_1F1_asymp_negx(a, b, x, result);    }    else {      return hyperg_1F1_luke(a, b, x, result);    }  }}/* 1F1(b+eps,b,x) * |eps|<=1, b > 0 */staticinthyperg_1F1_beps_bgt0(const double eps, const double b, const double x, gsl_sf_result * result){  if(b > fabs(x) && fabs(eps) < GSL_SQRT_DBL_EPSILON) {    /* If b-a is very small and x/b is not too large we can     * use this explicit approximation.     *     * 1F1(b+eps,b,x) = exp(ax/b) (1 - eps x^2 (v2 + v3 x + ...) + ...)     *     *   v2 = a/(2b^2(b+1))     *   v3 = a(b-2a)/(3b^3(b+1)(b+2))     *   ...     *     * See [Luke, Mathematical Functions and Their Approximations, p.292]     *     * This cannot be used for b near a negative integer or zero.     * Also, if x/b is large the deviation from exp(x) behaviour grows.     */    double a = b + eps;    gsl_sf_result exab;    int stat_e = gsl_sf_exp_e(a*x/b, &exab);    double v2 = a/(2.0*b*b*(b+1.0));    double v3 = a*(b-2.0*a)/(3.0*b*b*b*(b+1.0)*(b+2.0));    double v  = v2 + v3 * x;    double f  = (1.0 - eps*x*x*v);    result->val  = exab.val * f;    result->err  = exab.err * fabs(f);    result->err += fabs(exab.val) * GSL_DBL_EPSILON * (1.0 + fabs(eps*x*x*v));    result->err += 4.0 * GSL_DBL_EPSILON * fabs(result->val);    return stat_e;  }  else {    /* Otherwise use a Kummer transformation to reduce     * it to the small a case.     */    gsl_sf_result Kummer_1F1;    int stat_K = hyperg_1F1_small_a_bgt0(-eps, b, -x, &Kummer_1F1);    if(Kummer_1F1.val != 0.0) {      int stat_e = gsl_sf_exp_mult_err_e(x, 2.0*GSL_DBL_EPSILON*fabs(x),                                            Kummer_1F1.val, Kummer_1F1.err,                                            result);      return GSL_ERROR_SELECT_2(stat_e, stat_K);    }    else {      result->val = 0.0;      result->err = 0.0;      return stat_K;    }  }}/* 1F1(a,2a,x) = Gamma(a + 1/2) E(x) (|x|/4)^(-a+1/2) scaled_I(a-1/2,|x|/2) * * E(x) = exp(x) x > 0 *      = 1      x < 0 * * a >= 1/2 */staticinthyperg_1F1_beq2a_pos(const double a, const double x, gsl_sf_result * result){  if(x == 0.0) {    result->val = 1.0;    result->err = 0.0;    return GSL_SUCCESS;  }  else {    gsl_sf_result I;    int stat_I = gsl_sf_bessel_Inu_scaled_e(a-0.5, 0.5*fabs(x), &I);    gsl_sf_result lg;    int stat_g = gsl_sf_lngamma_e(a + 0.5, &lg);    double ln_term   = (0.5-a)*log(0.25*fabs(x));    double lnpre_val = lg.val + GSL_MAX_DBL(x,0.0) + ln_term;    double lnpre_err = lg.err + GSL_DBL_EPSILON * (fabs(ln_term) + fabs(x));    int stat_e = gsl_sf_exp_mult_err_e(lnpre_val, lnpre_err,    					  I.val, I.err,    					  result);    return GSL_ERROR_SELECT_3(stat_e, stat_g, stat_I);  }}/* Determine middle parts of diagonal recursion along b=2a * from two endpoints, i.e. * * given:  M(a,b)      and  M(a+1,b+2) * get:    M(a+1,b+1)  and  M(a,b+1) */#if 0inlinestaticinthyperg_1F1_diag_step(const double a, const double b, const double x,                     const double Mab, const double Map1bp2,                     double * Map1bp1, double * Mabp1){  if(a == b) {    *Map1bp1 = Mab;    *Mabp1   = Mab - x/(b+1.0) * Map1bp2;  }  else {    *Map1bp1 = Mab - x * (a-b)/(b*(b+1.0)) * Map1bp2;    *Mabp1   = (a * *Map1bp1 - b * Mab)/(a-b);  }  return GSL_SUCCESS;}#endif /* 0 *//* Determine endpoint of diagonal recursion. * * given:  M(a,b)    and  M(a+1,b+2) * get:    M(a+1,b)  and  M(a+1,b+1) */#if 0inlinestaticinthyperg_1F1_diag_end_step(const double a, const double b, const double x,                         const double Mab, const double Map1bp2,                         double * Map1b, double * Map1bp1){  *Map1bp1 = Mab - x * (a-b)/(b*(b+1.0)) * Map1bp2;  *Map1b   = Mab + x/b * *Map1bp1;  return GSL_SUCCESS;}#endif /* 0 *//* Handle the case of a and b both positive integers. * Assumes a > 0 and b > 0. */staticinthyperg_1F1_ab_posint(const int a, const int b, const double x, gsl_sf_result * result){  double ax = fabs(x);  if(a == b) {    return gsl_sf_exp_e(x, result);             /* 1F1(a,a,x) */  }  else if(a == 1) {    return gsl_sf_exprel_n_e(b-1, x, result);   /* 1F1(1,b,x) */  }  else if(b == a + 1) {    gsl_sf_result K;    int stat_K = gsl_sf_exprel_n_e(a, -x, &K);  /* 1F1(1,1+a,-x) */    int stat_e = gsl_sf_exp_mult_err_e(x, 2.0 * GSL_DBL_EPSILON * fabs(x),    					  K.val, K.err,    					  result);    return GSL_ERROR_SELECT_2(stat_e, stat_K);  }  else if(a == b + 1) {    gsl_sf_result ex;    int stat_e = gsl_sf_exp_e(x, &ex);    result->val  = ex.val * (1.0 + x/b);    result->err  = ex.err * (1.0 + x/b);    result->err += ex.val * GSL_DBL_EPSILON * (1.0 + fabs(x/b));    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);    return stat_e;  }  else if(a == b + 2) {    gsl_sf_result ex;    int stat_e = gsl_sf_exp_e(x, &ex);    double poly  = (1.0 + x/b*(2.0 + x/(b+1.0)));    result->val  = ex.val * poly;    result->err  = ex.err * fabs(poly);    result->err += ex.val * GSL_DBL_EPSILON * (1.0 + fabs(x/b) * (2.0 + fabs(x/(b+1.0))));    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);    return stat_e;  }  else if(b == 2*a) {    return hyperg_1F1_beq2a_pos(a, x, result);  /* 1F1(a,2a,x) */  }  else if(   ( b < 10 && a < 10 && ax < 5.0 )          || ( b > a*ax )	  || ( b > a && ax < 5.0 )    ) {    return gsl_sf_hyperg_1F1_series_e(a, b, x, result);  }  else if(b > a && b >= 2*a + x) {    /* Use the Gautschi CF series, then     * recurse backward to a=0 for normalization.     * This will work for either sign of x.     */    double rap;    int stat_CF1 = hyperg_1F1_CF1_p_ser(a, b, x, &rap);    double ra = 1.0 + x/a * rap;    double Ma	= GSL_SQRT_DBL_MIN;    double Map1 = ra * Ma;    double Mnp1 = Map1;    double Mn	= Ma;    double Mnm1;    int n;    for(n=a; n>0; n--) {      Mnm1 = (n * Mnp1 - (2*n-b+x) * Mn) / (b-n);      Mnp1 = Mn;      Mn   = Mnm1;    }    result->val = Ma/Mn;    result->err = 2.0 * GSL_DBL_EPSILON * (fabs(a) + 1.0) * fabs(Ma/Mn);    return stat_CF1;  }  else if(b > a && b < 2*a + x && b > x) {    /* Use the Gautschi series representation of     * the continued fraction. Then recurse forward     * to the a=b line for normalization. This will     * work for either sign of x, although we do need     * to check for b > x, for when x is positive.     */    double rap;    int stat_CF1 = hyperg_1F1_CF1_p_ser(a, b, x, &rap);    double ra = 1.0 + x/a * rap;    gsl_sf_result ex;    int stat_ex;    double Ma   = GSL_SQRT_DBL_MIN;    double Map1 = ra * Ma;    double Mnm1 = Ma;    double Mn	= Map1;    double Mnp1;    int n;    for(n=a+1; n<b; n++) {      Mnp1 = ((b-n)*Mnm1 + (2*n-b+x)*Mn)/n;      Mnm1 = Mn;      Mn   = Mnp1;    }    stat_ex = gsl_sf_exp_e(x, &ex);  /* 1F1(b,b,x) */    result->val  = ex.val * Ma/Mn;    result->err  = ex.err * fabs(Ma/Mn);    result->err += 4.0 * GSL_DBL_EPSILON * (fabs(b-a)+1.0) * fabs(result->val);    return GSL_ERROR_SELECT_2(stat_ex, stat_CF1);  }  else if(x >= 0.0) {    if(b < a) {      /* The point b,b is below the b=2a+x line.       * Forward recursion on a from b,b+1 is possible.       * Note that a > b + 1 as well, since we already tried a = b + 1.       */      if(x + log(fabs(x/b)) < GSL_LOG_DBL_MAX-2.0) {        double ex = exp(x);        int n;        double Mnm1 = ex;		  /* 1F1(b,b,x)   */    	double Mn   = ex * (1.0 + x/b);   /* 1F1(b+1,b,x) */    	double Mnp1;        for(n=b+1; n<a; n++) {          Mnp1 = ((b-n)*Mnm1 + (2*n-b+x)*Mn)/n;          Mnm1 = Mn;          Mn   = Mnp1;        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -