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

📄 hyperg_2f1.c

📁 开放gsl矩阵运算
💻 C
📖 第 1 页 / 共 2 页
字号:
/* specfunc/hyperg_2F1.c *  * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman *  * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. *  * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Author:  G. Jungman */#include <config.h>#include <gsl/gsl_math.h>#include <gsl/gsl_errno.h>#include "gsl_sf_exp.h"#include "gsl_sf_pow_int.h"#include "gsl_sf_gamma.h"#include "gsl_sf_psi.h"#include "gsl_sf_hyperg.h"#include "error.h"#define locEPS (1000.0*GSL_DBL_EPSILON)/* Assumes c != negative integer. */static inthyperg_2F1_series(const double a, const double b, const double c,                  const double x, 		  gsl_sf_result * result		  ){  double sum_pos = 1.0;  double sum_neg = 0.0;  double del_pos = 1.0;  double del_neg = 0.0;  double del = 1.0;  double k = 0.0;  int i = 0;  if(fabs(c) < GSL_DBL_EPSILON) {    result->val = 0.0; /* FIXME: ?? */    result->err = 1.0;    GSL_ERROR ("error", GSL_EDOM);  }  do {    if(++i > 30000) {      result->val  = sum_pos - sum_neg;      result->err  = del_pos + del_neg;      result->err += 2.0 * GSL_DBL_EPSILON * (sum_pos + sum_neg);      result->err += 2.0 * GSL_DBL_EPSILON * (2.0*sqrt(k)+1.0) * fabs(result->val);      GSL_ERROR ("error", GSL_EMAXITER);    }    del *= (a+k)*(b+k) * x / ((c+k) * (k+1.0));  /* Gauss series */    if(del > 0.0) {      del_pos  =  del;      sum_pos +=  del;    }    else if(del == 0.0) {      /* Exact termination (a or b was a negative integer).       */      del_pos = 0.0;      del_neg = 0.0;      break;    }    else {      del_neg  = -del;      sum_neg -=  del;    }    k += 1.0;  } while(fabs((del_pos + del_neg)/(sum_pos-sum_neg)) > GSL_DBL_EPSILON);  result->val  = sum_pos - sum_neg;  result->err  = del_pos + del_neg;  result->err += 2.0 * GSL_DBL_EPSILON * (sum_pos + sum_neg);  result->err += 2.0 * GSL_DBL_EPSILON * (2.0*sqrt(k) + 1.0) * fabs(result->val);  return GSL_SUCCESS;}/* a = aR + i aI, b = aR - i aI */staticinthyperg_2F1_conj_series(const double aR, const double aI, const double c,                       double x,		       gsl_sf_result * result){  if(c == 0.0) {    result->val = 0.0; /* FIXME: should be Inf */    result->err = 0.0;    GSL_ERROR ("error", GSL_EDOM);  }  else {    double sum_pos = 1.0;    double sum_neg = 0.0;    double del_pos = 1.0;    double del_neg = 0.0;    double del = 1.0;    double k = 0.0;    do {      del *= ((aR+k)*(aR+k) + aI*aI)/((k+1.0)*(c+k)) * x;      if(del >= 0.0) {        del_pos  =  del;        sum_pos +=  del;      }      else {        del_neg  = -del;        sum_neg -=  del;      }      if(k > 30000) {        result->val  = sum_pos - sum_neg;        result->err  = del_pos + del_neg;        result->err += 2.0 * GSL_DBL_EPSILON * (sum_pos + sum_neg);        result->err += 2.0 * GSL_DBL_EPSILON * (2.0*sqrt(k)+1.0) * fabs(result->val);        GSL_ERROR ("error", GSL_EMAXITER);      }      k += 1.0;    } while(fabs((del_pos + del_neg)/(sum_pos - sum_neg)) > GSL_DBL_EPSILON);    result->val  = sum_pos - sum_neg;    result->err  = del_pos + del_neg;    result->err += 2.0 * GSL_DBL_EPSILON * (sum_pos + sum_neg);    result->err += 2.0 * GSL_DBL_EPSILON * (2.0*sqrt(k) + 1.0) * fabs(result->val);    return GSL_SUCCESS;  }}/* Luke's rational approximation. The most accesible * discussion is in [Kolbig, CPC 23, 51 (1981)]. * The convergence is supposedly guaranteed for x < 0. * You have to read Luke's books to see this and other * results. Unfortunately, the stability is not so * clear to me, although it seems very efficient when * it works. */staticinthyperg_2F1_luke(const double a, const double b, const double c,                const double xin,                 gsl_sf_result * result){  int stat_iter;  const double RECUR_BIG = 1.0e+50;  const int nmax = 20000;  int n = 3;  const double x  = -xin;  const double x3 = x*x*x;  const double t0 = a*b/c;  const double t1 = (a+1.0)*(b+1.0)/(2.0*c);  const double t2 = (a+2.0)*(b+2.0)/(2.0*(c+1.0));  double F = 1.0;  double prec;  double Bnm3 = 1.0;                                  /* B0 */  double Bnm2 = 1.0 + t1 * x;                         /* B1 */  double Bnm1 = 1.0 + t2 * x * (1.0 + t1/3.0 * x);    /* B2 */   double Anm3 = 1.0;                                                      /* A0 */  double Anm2 = Bnm2 - t0 * x;                                            /* A1 */  double Anm1 = Bnm1 - t0*(1.0 + t2*x)*x + t0 * t1 * (c/(c+1.0)) * x*x;   /* A2 */  while(1) {    double npam1 = n + a - 1;    double npbm1 = n + b - 1;    double npcm1 = n + c - 1;    double npam2 = n + a - 2;    double npbm2 = n + b - 2;    double npcm2 = n + c - 2;    double tnm1  = 2*n - 1;    double tnm3  = 2*n - 3;    double tnm5  = 2*n - 5;    double n2 = n*n;    double F1 =  (3.0*n2 + (a+b-6)*n + 2 - a*b - 2*(a+b)) / (2*tnm3*npcm1);    double F2 = -(3.0*n2 - (a+b+6)*n + 2 - a*b)*npam1*npbm1/(4*tnm1*tnm3*npcm2*npcm1);    double F3 = (npam2*npam1*npbm2*npbm1*(n-a-2)*(n-b-2)) / (8*tnm3*tnm3*tnm5*(n+c-3)*npcm2*npcm1);    double E  = -npam1*npbm1*(n-c-1) / (2*tnm3*npcm2*npcm1);    double An = (1.0+F1*x)*Anm1 + (E + F2*x)*x*Anm2 + F3*x3*Anm3;    double Bn = (1.0+F1*x)*Bnm1 + (E + F2*x)*x*Bnm2 + F3*x3*Bnm3;    double r = An/Bn;    prec = fabs((F - r)/F);    F = r;    if(prec < GSL_DBL_EPSILON || n > nmax) break;    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;      Anm3 /= RECUR_BIG;      Bnm3 /= RECUR_BIG;    }    else if(fabs(An) < 1.0/RECUR_BIG || fabs(Bn) < 1.0/RECUR_BIG) {      An   *= RECUR_BIG;      Bn   *= RECUR_BIG;      Anm1 *= RECUR_BIG;      Bnm1 *= RECUR_BIG;      Anm2 *= RECUR_BIG;      Bnm2 *= RECUR_BIG;      Anm3 *= RECUR_BIG;      Bnm3 *= RECUR_BIG;    }    n++;    Bnm3 = Bnm2;    Bnm2 = Bnm1;    Bnm1 = Bn;    Anm3 = Anm2;    Anm2 = Anm1;    Anm1 = An;  }  result->val  = F;  result->err  = 2.0 * fabs(prec * F);  result->err += 2.0 * GSL_DBL_EPSILON * (n+1.0) * fabs(F);  /* FIXME: just a hack: there's a lot of shit going on here */  result->err *= 8.0 * (fabs(a) + fabs(b) + 1.0);  stat_iter = (n >= nmax ? GSL_EMAXITER : GSL_SUCCESS );  return stat_iter;}/* Luke's rational approximation for the * case a = aR + i aI, b = aR - i aI. */staticinthyperg_2F1_conj_luke(const double aR, const double aI, const double c,                     const double xin,                      gsl_sf_result * result){  int stat_iter;  const double RECUR_BIG = 1.0e+50;  const int nmax = 10000;  int n = 3;  const double x = -xin;  const double x3 = x*x*x;  const double atimesb = aR*aR + aI*aI;  const double apb     = 2.0*aR;  const double t0 = atimesb/c;  const double t1 = (atimesb +     apb + 1.0)/(2.0*c);  const double t2 = (atimesb + 2.0*apb + 4.0)/(2.0*(c+1.0));  double F = 1.0;  double prec;  double Bnm3 = 1.0;                                  /* B0 */  double Bnm2 = 1.0 + t1 * x;                         /* B1 */  double Bnm1 = 1.0 + t2 * x * (1.0 + t1/3.0 * x);    /* B2 */   double Anm3 = 1.0;                                                      /* A0 */  double Anm2 = Bnm2 - t0 * x;                                            /* A1 */  double Anm1 = Bnm1 - t0*(1.0 + t2*x)*x + t0 * t1 * (c/(c+1.0)) * x*x;   /* A2 */  while(1) {    double nm1 = n - 1;    double nm2 = n - 2;    double npam1_npbm1 = atimesb + nm1*apb + nm1*nm1;    double npam2_npbm2 = atimesb + nm2*apb + nm2*nm2;    double npcm1 = nm1 + c;    double npcm2 = nm2 + c;    double tnm1  = 2*n - 1;    double tnm3  = 2*n - 3;    double tnm5  = 2*n - 5;    double n2 = n*n;    double F1 =  (3.0*n2 + (apb-6)*n + 2 - atimesb - 2*apb) / (2*tnm3*npcm1);    double F2 = -(3.0*n2 - (apb+6)*n + 2 - atimesb)*npam1_npbm1/(4*tnm1*tnm3*npcm2*npcm1);    double F3 = (npam2_npbm2*npam1_npbm1*(nm2*nm2 - nm2*apb + atimesb)) / (8*tnm3*tnm3*tnm5*(n+c-3)*npcm2*npcm1);    double E  = -npam1_npbm1*(n-c-1) / (2*tnm3*npcm2*npcm1);    double An = (1.0+F1*x)*Anm1 + (E + F2*x)*x*Anm2 + F3*x3*Anm3;    double Bn = (1.0+F1*x)*Bnm1 + (E + F2*x)*x*Bnm2 + F3*x3*Bnm3;    double r = An/Bn;    prec = fabs(F - r)/fabs(F);    F = r;    if(prec < GSL_DBL_EPSILON || n > nmax) break;    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;      Anm3 /= RECUR_BIG;      Bnm3 /= RECUR_BIG;    }    else if(fabs(An) < 1.0/RECUR_BIG || fabs(Bn) < 1.0/RECUR_BIG) {      An   *= RECUR_BIG;      Bn   *= RECUR_BIG;      Anm1 *= RECUR_BIG;      Bnm1 *= RECUR_BIG;      Anm2 *= RECUR_BIG;      Bnm2 *= RECUR_BIG;      Anm3 *= RECUR_BIG;      Bnm3 *= RECUR_BIG;    }    n++;    Bnm3 = Bnm2;    Bnm2 = Bnm1;    Bnm1 = Bn;    Anm3 = Anm2;    Anm2 = Anm1;    Anm1 = An;  }    result->val  = F;  result->err  = 2.0 * fabs(prec * F);  result->err += 2.0 * GSL_DBL_EPSILON * (n+1.0) * fabs(F);  /* FIXME: see above */  result->err *= 8.0 * (fabs(aR) + fabs(aI) + 1.0);  stat_iter = (n >= nmax ? GSL_EMAXITER : GSL_SUCCESS );  return stat_iter;}/* Do the reflection described in [Moshier, p. 334]. * Assumes a,b,c != neg integer. */staticinthyperg_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 = 1000;      int i;      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);

⌨️ 快捷键说明

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