diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-11-22 14:04:29 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-11-22 14:04:29 +0000 |
commit | 7ce331c01ce6eb7b3f5c715a38a24359da9c6ee2 (patch) | |
tree | 3a7e8476e868ae15f4da1b7ce26b2db6f434468c /libm/float/hypergf.c | |
parent | c117dd5fb183afb1a4790a6f6110d88704be6bf8 (diff) |
Totally rework the math library, this time based on the MacOs X
math library (which is itself based on the math lib from FreeBSD).
-Erik
Diffstat (limited to 'libm/float/hypergf.c')
-rw-r--r-- | libm/float/hypergf.c | 384 |
1 files changed, 0 insertions, 384 deletions
diff --git a/libm/float/hypergf.c b/libm/float/hypergf.c deleted file mode 100644 index 60d0eb4c5..000000000 --- a/libm/float/hypergf.c +++ /dev/null @@ -1,384 +0,0 @@ -/* 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 ); -} |