123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /* hypergf.c
- *
- * Confluent hypergeometric function
- *
- *
- *
- * SYNOPSIS:
- *
- * float a, b, x, y, hypergf();
- *
- * y = hypergf( 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
- * IEEE 0,5 10000 6.6e-7 1.3e-7
- * IEEE 0,30 30000 1.1e-5 6.5e-7
- *
- * 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-3.
- *
- */
- /* hyperg.c */
- /*
- Cephes Math Library Release 2.1: November, 1988
- Copyright 1984, 1987, 1988 by Stephen L. Moshier
- Direct inquiries to 30 Frost Street, Cambridge, MA 02140
- */
- #include <math.h>
- extern float MAXNUMF, MACHEPF;
- #define fabsf(x) ( (x) < 0 ? -(x) : (x) )
- #ifdef ANSIC
- float expf(float);
- float hyp2f0f(float, float, float, int, float *);
- static float hy1f1af(float, float, float, float *);
- static float hy1f1pf(float, float, float, float *);
- float logf(float), gammaf(float), lgamf(float);
- #else
- float expf(), hyp2f0f();
- float logf(), gammaf(), lgamf();
- static float hy1f1pf(), hy1f1af();
- #endif
- float hypergf( float aa, float bb, float xx )
- {
- float a, b, x, asum, psum, acanc, pcanc, temp;
- a = aa;
- b = bb;
- x = xx;
- /* See if a Kummer transformation will help */
- temp = b - a;
- if( fabsf(temp) < 0.001 * fabsf(a) )
- return( expf(x) * hypergf( temp, b, -x ) );
- psum = hy1f1pf( a, b, x, &pcanc );
- if( pcanc < 1.0e-6 )
- goto done;
- /* try asymptotic series */
- asum = hy1f1af( a, b, x, &acanc );
- /* Pick the result with less estimated error */
- if( acanc < pcanc )
- {
- pcanc = acanc;
- psum = asum;
- }
- done:
- if( pcanc > 1.0e-3 )
- mtherr( "hyperg", PLOSS );
- return( psum );
- }
- /* Power series summation for confluent hypergeometric function */
- static float hy1f1pf( float aa, float bb, float xx, float *err )
- {
- float a, b, x, n, a0, sum, t, u, temp;
- float an, bn, maxt, pcanc;
- a = aa;
- b = bb;
- x = xx;
- /* 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 > MACHEPF )
- {
- if( bn == 0 ) /* check bn first since if both */
- {
- mtherr( "hypergf", SING );
- return( MAXNUMF ); /* 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 = fabsf(u);
- if( (temp > 1.0 ) && (maxt > (MAXNUMF/temp)) )
- {
- pcanc = 1.0; /* estimate 100% error */
- goto blowup;
- }
- a0 *= u;
- sum += a0;
- t = fabsf(a0);
- if( t > maxt )
- maxt = t;
- /*
- if( (maxt/fabsf(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 /= fabsf(sum);
- maxt *= MACHEPF; /* this way avoids multiply overflow */
- pcanc = fabsf( MACHEPF * 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 float hy1f1af( float aa, float bb, float xx, float *err )
- {
- float a, b, x, h1, h2, t, u, temp, acanc, asum, err1, err2;
- a = aa;
- b = bb;
- x = xx;
- if( x == 0 )
- {
- acanc = 1.0;
- asum = MAXNUMF;
- goto adone;
- }
- temp = logf( fabsf(x) );
- t = x + temp * (a-b);
- u = -temp * a;
- if( b > 0 )
- {
- temp = lgamf(b);
- t += temp;
- u += temp;
- }
- h1 = hyp2f0f( a, a-b+1, -1.0/x, 1, &err1 );
- temp = expf(u) / gammaf(b-a);
- h1 *= temp;
- err1 *= temp;
- h2 = hyp2f0f( b-a, 1.0-a, 1.0/x, 2, &err2 );
- if( a < 0 )
- temp = expf(t) / gammaf(a);
- else
- temp = expf( t - lgamf(a) );
- h2 *= temp;
- err2 *= temp;
- if( x < 0.0 )
- asum = h1;
- else
- asum = h2;
- acanc = fabsf(err1) + fabsf(err2);
- if( b < 0 )
- {
- temp = gammaf(b);
- asum *= temp;
- acanc *= fabsf(temp);
- }
- if( asum != 0.0 )
- acanc /= fabsf(asum);
- acanc *= 30.0; /* fudge factor, since error of asymptotic formula
- * often seems this much larger than advertised */
- adone:
- *err = acanc;
- return( asum );
- }
- /* hyp2f0() */
- float hyp2f0f(float aa, float bb, float xx, int type, float *err)
- {
- float a, b, x, a0, alast, t, tlast, maxt;
- float n, an, bn, u, sum, temp;
- a = aa;
- b = bb;
- x = xx;
- an = a;
- bn = b;
- a0 = 1.0;
- alast = 1.0;
- sum = 0.0;
- n = 1.0;
- t = 1.0;
- 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 = fabsf(u);
- if( (temp > 1.0 ) && (maxt > (MAXNUMF/temp)) )
- goto error;
- a0 *= u;
- t = fabsf(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.0;
- bn += 1.0;
- n += 1.0;
- if( t > maxt )
- maxt = t;
- }
- while( t > MACHEPF );
- pdone: /* series converged! */
- /* estimate error due to roundoff and cancellation */
- *err = fabsf( MACHEPF * (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 = MACHEPF * (n + maxt) + fabsf( a0 );
- done:
- sum += alast;
- return( sum );
- /* series blew up: */
- error:
- *err = MAXNUMF;
- mtherr( "hypergf", TLOSS );
- return( sum );
- }
|