📄 hyperg_1f1.c
字号:
inthyperg_1F1_renorm_b0(const double a, const double x, gsl_sf_result * result){ double eta = a*x; if(eta > 0.0) { double root_eta = sqrt(eta); gsl_sf_result I1_scaled; int stat_I = gsl_sf_bessel_I1_scaled_e(2.0*root_eta, &I1_scaled); if(I1_scaled.val <= 0.0) { result->val = 0.0; result->err = 0.0; return GSL_ERROR_SELECT_2(stat_I, GSL_EDOM); } else { /* Note that 13.3.7 contains higher terms which are zeroth order in b. These make a non-negligible contribution to the sum. With the first correction term, the I1 above is replaced by I1 + (2/3)*a*(x/(4a))**(3/2)*I2(2*root_eta). We will add this as part of the result and error estimate. */ const double corr1 =(2.0/3.0)*a*pow(x/(4.0*a),1.5)*gsl_sf_bessel_In_scaled(2, 2.0*root_eta) ; const double lnr_val = 0.5*x + 0.5*log(eta) + fabs(2.0*root_eta) + log(I1_scaled.val+corr1); const double lnr_err = GSL_DBL_EPSILON * (1.5*fabs(x) + 1.0) + fabs((I1_scaled.err+corr1)/I1_scaled.val); return gsl_sf_exp_err_e(lnr_val, lnr_err, result); } } else if(eta == 0.0) { result->val = 0.0; result->err = 0.0; return GSL_SUCCESS; } else { /* eta < 0 */ double root_eta = sqrt(-eta); gsl_sf_result J1; int stat_J = gsl_sf_bessel_J1_e(2.0*root_eta, &J1); if(J1.val <= 0.0) { result->val = 0.0; result->err = 0.0; return GSL_ERROR_SELECT_2(stat_J, GSL_EDOM); } else { const double t1 = 0.5*x; const double t2 = 0.5*log(-eta); const double t3 = fabs(x); const double t4 = log(J1.val); const double lnr_val = t1 + t2 + t3 + t4; const double lnr_err = GSL_DBL_EPSILON * (1.5*fabs(x) + 1.0) + fabs(J1.err/J1.val); gsl_sf_result ex; int stat_e = gsl_sf_exp_err_e(lnr_val, lnr_err, &ex); result->val = -ex.val; result->err = ex.err; return stat_e; } } }/* 1F1'(a,b,x)/1F1(a,b,x) * Uses Gautschi's version of the CF. * [Gautschi, Math. Comp. 31, 994 (1977)] * * Supposedly this suffers from the "anomalous convergence" * problem when b < x. I have seen anomalous convergence * in several of the continued fractions associated with * 1F1(a,b,x). This particular CF formulation seems stable * for b > x. However, it does display a painful artifact * of the anomalous convergence; the convergence plateaus * unless b >>> x. For example, even for b=1000, x=1, this * method locks onto a ratio which is only good to about * 4 digits. Apparently the rest of the digits are hiding * way out on the plateau, but finite-precision lossage * means you will never get them. */#if 0staticinthyperg_1F1_CF1_p(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 = 1.0; double b1 = 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)*x/((b-x+n-1)*(b-x+n)); bn = 1.0; 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 = a/(b-x) * fn; if(n == maxiter) GSL_ERROR ("error", GSL_EMAXITER); else return GSL_SUCCESS;}#endif /* 0 *//* 1F1'(a,b,x)/1F1(a,b,x) * Uses Gautschi's series transformation of the * continued fraction. This is apparently the best * method for getting this ratio in the stable region. * The convergence is monotone and supergeometric * when b > x. * Assumes a >= -1. */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 && b >= 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 if (fabs(x) < fabs(b) && fabs(a*x) < sqrt(fabs(b)) * fabs(b-x)) { return hyperg_1F1_largebx(a, b, x, result); } 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -