123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- /* hyperg.c
- *
- * Confluent hypergeometric function
- *
- *
- *
- * SYNOPSIS:
- *
- * double a, b, x, y, hyperg();
- *
- * y = hyperg( a, b, x );
- *
- *
- *
- * DESCRIPTION:
- *
- * Computes the confluent hypergeometric function
- *
- * 1 2
- * a x a(a+1) x
- * F ( a,b;x ) = 1 + ---- + --------- + ...
- * 1 1 b 1! b(b+1) 2!
- *
- * Many higher transcendental functions are special cases of
- * this power series.
- *
- * As is evident from the formula, b must not be a negative
- * integer or zero unless a is an integer with 0 >= a > b.
- *
- * The routine attempts both a direct summation of the series
- * and an asymptotic expansion. In each case error due to
- * roundoff, cancellation, and nonconvergence is estimated.
- * The result with smaller estimated error is returned.
- *
- *
- *
- * ACCURACY:
- *
- * Tested at random points (a, b, x), all three variables
- * ranging from 0 to 30.
- * Relative error:
- * arithmetic domain # trials peak rms
- * DEC 0,30 2000 1.2e-15 1.3e-16
- qtst1:
- 21800 max = 1.4200E-14 rms = 1.0841E-15 ave = -5.3640E-17
- ltstd:
- 25500 max = 1.2759e-14 rms = 3.7155e-16 ave = 1.5384e-18
- * IEEE 0,30 30000 1.8e-14 1.1e-15
- *
- * Larger errors can be observed when b is near a negative
- * integer or zero. Certain combinations of arguments yield
- * serious cancellation error in the power series summation
- * and also are not in the region of near convergence of the
- * asymptotic series. An error message is printed if the
- * self-estimated relative error is greater than 1.0e-12.
- *
- */
- /* hyperg.c */
- /*
- Cephes Math Library Release 2.8: June, 2000
- Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier
- */
- #include <math.h>
- #ifdef ANSIPROT
- extern double exp ( double );
- extern double log ( double );
- extern double gamma ( double );
- extern double lgam ( double );
- extern double fabs ( double );
- double hyp2f0 ( double, double, double, int, double * );
- static double hy1f1p(double, double, double, double *);
- static double hy1f1a(double, double, double, double *);
- double hyperg (double, double, double);
- #else
- double exp(), log(), gamma(), lgam(), fabs(), hyp2f0();
- static double hy1f1p();
- static double hy1f1a();
- double hyperg();
- #endif
- extern double MAXNUM, MACHEP;
- double hyperg( a, b, x)
- double a, b, x;
- {
- double asum, psum, acanc, pcanc, temp;
- /* See if a Kummer transformation will help */
- temp = b - a;
- if( fabs(temp) < 0.001 * fabs(a) )
- return( exp(x) * hyperg( temp, b, -x ) );
- psum = hy1f1p( a, b, x, &pcanc );
- if( pcanc < 1.0e-15 )
- goto done;
- /* try asymptotic series */
- asum = hy1f1a( a, b, x, &acanc );
- /* Pick the result with less estimated error */
- if( acanc < pcanc )
- {
- pcanc = acanc;
- psum = asum;
- }
- done:
- if( pcanc > 1.0e-12 )
- mtherr( "hyperg", PLOSS );
- return( psum );
- }
- /* Power series summation for confluent hypergeometric function */
- static double hy1f1p( a, b, x, err )
- double a, b, x;
- double *err;
- {
- double n, a0, sum, t, u, temp;
- double an, bn, maxt, pcanc;
- /* set up for power series summation */
- an = a;
- bn = b;
- a0 = 1.0;
- sum = 1.0;
- n = 1.0;
- t = 1.0;
- maxt = 0.0;
- while( t > MACHEP )
- {
- if( bn == 0 ) /* check bn first since if both */
- {
- mtherr( "hyperg", SING );
- return( MAXNUM ); /* an and bn are zero it is */
- }
- if( an == 0 ) /* a singularity */
- return( sum );
- if( n > 200 )
- goto pdone;
- u = x * ( an / (bn * n) );
- /* check for blowup */
- temp = fabs(u);
- if( (temp > 1.0 ) && (maxt > (MAXNUM/temp)) )
- {
- pcanc = 1.0; /* estimate 100% error */
- goto blowup;
- }
- a0 *= u;
- sum += a0;
- t = fabs(a0);
- if( t > maxt )
- maxt = t;
- /*
- if( (maxt/fabs(sum)) > 1.0e17 )
- {
- pcanc = 1.0;
- goto blowup;
- }
- */
- an += 1.0;
- bn += 1.0;
- n += 1.0;
- }
- pdone:
- /* estimate error due to roundoff and cancellation */
- if( sum != 0.0 )
- maxt /= fabs(sum);
- maxt *= MACHEP; /* this way avoids multiply overflow */
- pcanc = fabs( MACHEP * n + maxt );
- blowup:
- *err = pcanc;
- return( sum );
- }
- /* hy1f1a() */
- /* asymptotic formula for hypergeometric function:
- *
- * ( -a
- * -- ( |z|
- * | (b) ( -------- 2f0( a, 1+a-b, -1/x )
- * ( --
- * ( | (b-a)
- *
- *
- * x a-b )
- * e |x| )
- * + -------- 2f0( b-a, 1-a, 1/x ) )
- * -- )
- * | (a) )
- */
- static double hy1f1a( a, b, x, err )
- double a, b, x;
- double *err;
- {
- double h1, h2, t, u, temp, acanc, asum, err1, err2;
- if( x == 0 )
- {
- acanc = 1.0;
- asum = MAXNUM;
- goto adone;
- }
- temp = log( fabs(x) );
- t = x + temp * (a-b);
- u = -temp * a;
- if( b > 0 )
- {
- temp = lgam(b);
- t += temp;
- u += temp;
- }
- h1 = hyp2f0( a, a-b+1, -1.0/x, 1, &err1 );
- temp = exp(u) / gamma(b-a);
- h1 *= temp;
- err1 *= temp;
- h2 = hyp2f0( b-a, 1.0-a, 1.0/x, 2, &err2 );
- if( a < 0 )
- temp = exp(t) / gamma(a);
- else
- temp = exp( t - lgam(a) );
- h2 *= temp;
- err2 *= temp;
- if( x < 0.0 )
- asum = h1;
- else
- asum = h2;
- acanc = fabs(err1) + fabs(err2);
- if( b < 0 )
- {
- temp = gamma(b);
- asum *= temp;
- acanc *= fabs(temp);
- }
- if( asum != 0.0 )
- acanc /= fabs(asum);
- acanc *= 30.0; /* fudge factor, since error of asymptotic formula
- * often seems this much larger than advertised */
- adone:
- *err = acanc;
- return( asum );
- }
- /* hyp2f0() */
- double hyp2f0( a, b, x, type, err )
- double a, b, x;
- int type; /* determines what converging factor to use */
- double *err;
- {
- double a0, alast, t, tlast, maxt;
- double n, an, bn, u, sum, temp;
- an = a;
- bn = b;
- a0 = 1.0e0;
- alast = 1.0e0;
- sum = 0.0;
- n = 1.0e0;
- t = 1.0e0;
- tlast = 1.0e9;
- maxt = 0.0;
- do
- {
- if( an == 0 )
- goto pdone;
- if( bn == 0 )
- goto pdone;
- u = an * (bn * x / n);
- /* check for blowup */
- temp = fabs(u);
- if( (temp > 1.0 ) && (maxt > (MAXNUM/temp)) )
- goto error;
- a0 *= u;
- t = fabs(a0);
- /* terminating condition for asymptotic series */
- if( t > tlast )
- goto ndone;
- tlast = t;
- sum += alast; /* the sum is one term behind */
- alast = a0;
- if( n > 200 )
- goto ndone;
- an += 1.0e0;
- bn += 1.0e0;
- n += 1.0e0;
- if( t > maxt )
- maxt = t;
- }
- while( t > MACHEP );
- pdone: /* series converged! */
- /* estimate error due to roundoff and cancellation */
- *err = fabs( MACHEP * (n + maxt) );
- alast = a0;
- goto done;
- ndone: /* series did not converge */
- /* The following "Converging factors" are supposed to improve accuracy,
- * but do not actually seem to accomplish very much. */
- n -= 1.0;
- x = 1.0/x;
- switch( type ) /* "type" given as subroutine argument */
- {
- case 1:
- alast *= ( 0.5 + (0.125 + 0.25*b - 0.5*a + 0.25*x - 0.25*n)/x );
- break;
- case 2:
- alast *= 2.0/3.0 - b + 2.0*a + x - n;
- break;
- default:
- ;
- }
- /* estimate error due to roundoff, cancellation, and nonconvergence */
- *err = MACHEP * (n + maxt) + fabs ( a0 );
- done:
- sum += alast;
- return( sum );
- /* series blew up: */
- error:
- *err = MAXNUM;
- mtherr( "hyperg", TLOSS );
- return( sum );
- }
|