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/gammaf.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/gammaf.c')
-rw-r--r-- | libm/float/gammaf.c | 423 |
1 files changed, 0 insertions, 423 deletions
diff --git a/libm/float/gammaf.c b/libm/float/gammaf.c deleted file mode 100644 index e8c4694c4..000000000 --- a/libm/float/gammaf.c +++ /dev/null @@ -1,423 +0,0 @@ -/* gammaf.c - * - * Gamma function - * - * - * - * SYNOPSIS: - * - * float x, y, gammaf(); - * extern int sgngamf; - * - * y = gammaf( x ); - * - * - * - * DESCRIPTION: - * - * Returns gamma function of the argument. The result is - * correctly signed, and the sign (+1 or -1) is also - * returned in a global (extern) variable named sgngamf. - * This same variable is also filled in by the logarithmic - * gamma function lgam(). - * - * Arguments between 0 and 10 are reduced by recurrence and the - * function is approximated by a polynomial function covering - * the interval (2,3). Large arguments are handled by Stirling's - * formula. Negative arguments are made positive using - * a reflection formula. - * - * - * ACCURACY: - * - * Relative error: - * arithmetic domain # trials peak rms - * IEEE 0,-33 100,000 5.7e-7 1.0e-7 - * IEEE -33,0 100,000 6.1e-7 1.2e-7 - * - * - */ -/* lgamf() - * - * Natural logarithm of gamma function - * - * - * - * SYNOPSIS: - * - * float x, y, lgamf(); - * extern int sgngamf; - * - * y = lgamf( x ); - * - * - * - * DESCRIPTION: - * - * Returns the base e (2.718...) logarithm of the absolute - * value of the gamma function of the argument. - * The sign (+1 or -1) of the gamma function is returned in a - * global (extern) variable named sgngamf. - * - * For arguments greater than 6.5, the logarithm of the gamma - * function is approximated by the logarithmic version of - * Stirling's formula. Arguments between 0 and +6.5 are reduced by - * by recurrence to the interval [.75,1.25] or [1.5,2.5] of a rational - * approximation. The cosecant reflection formula is employed for - * arguments less than zero. - * - * Arguments greater than MAXLGM = 2.035093e36 return MAXNUM and an - * error message. - * - * - * - * ACCURACY: - * - * - * - * arithmetic domain # trials peak rms - * IEEE -100,+100 500,000 7.4e-7 6.8e-8 - * The error criterion was relative when the function magnitude - * was greater than one but absolute when it was less than one. - * The routine has low relative error for positive arguments. - * - * The following test used the relative error criterion. - * IEEE -2, +3 100000 4.0e-7 5.6e-8 - * - */ - -/* gamma.c */ -/* gamma function */ - -/* -Cephes Math Library Release 2.7: July, 1998 -Copyright 1984, 1987, 1989, 1992, 1998 by Stephen L. Moshier -*/ - - -#include <math.h> - -/* define MAXGAM 34.84425627277176174 */ - -/* Stirling's formula for the gamma function - * gamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) ( 1 + 1/x P(1/x) ) - * .028 < 1/x < .1 - * relative error < 1.9e-11 - */ -static float STIR[] = { --2.705194986674176E-003, - 3.473255786154910E-003, - 8.333331788340907E-002, -}; -static float MAXSTIR = 26.77; -static float SQTPIF = 2.50662827463100050242; /* sqrt( 2 pi ) */ - -int sgngamf = 0; -extern int sgngamf; -extern float MAXLOGF, MAXNUMF, PIF; - -#ifdef ANSIC -float expf(float); -float logf(float); -float powf( float, float ); -float sinf(float); -float gammaf(float); -float floorf(float); -static float stirf(float); -float polevlf( float, float *, int ); -float p1evlf( float, float *, int ); -#else -float expf(), logf(), powf(), sinf(), floorf(); -float polevlf(), p1evlf(); -static float stirf(); -#endif - -/* Gamma function computed by Stirling's formula, - * sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) - * The polynomial STIR is valid for 33 <= x <= 172. - */ -static float stirf( float xx ) -{ -float x, y, w, v; - -x = xx; -w = 1.0/x; -w = 1.0 + w * polevlf( w, STIR, 2 ); -y = expf( -x ); -if( x > MAXSTIR ) - { /* Avoid overflow in pow() */ - v = powf( x, 0.5 * x - 0.25 ); - y *= v; - y *= v; - } -else - { - y = powf( x, x - 0.5 ) * y; - } -y = SQTPIF * y * w; -return( y ); -} - - -/* gamma(x+2), 0 < x < 1 */ -static float P[] = { - 1.536830450601906E-003, - 5.397581592950993E-003, - 4.130370201859976E-003, - 7.232307985516519E-002, - 8.203960091619193E-002, - 4.117857447645796E-001, - 4.227867745131584E-001, - 9.999999822945073E-001, -}; - -float gammaf( float xx ) -{ -float p, q, x, z, nz; -int i, direction, negative; - -x = xx; -sgngamf = 1; -negative = 0; -nz = 0.0; -if( x < 0.0 ) - { - negative = 1; - q = -x; - p = floorf(q); - if( p == q ) - goto goverf; - i = p; - if( (i & 1) == 0 ) - sgngamf = -1; - nz = q - p; - if( nz > 0.5 ) - { - p += 1.0; - nz = q - p; - } - nz = q * sinf( PIF * nz ); - if( nz == 0.0 ) - { -goverf: - mtherr( "gamma", OVERFLOW ); - return( sgngamf * MAXNUMF); - } - if( nz < 0 ) - nz = -nz; - x = q; - } -if( x >= 10.0 ) - { - z = stirf(x); - } -if( x < 2.0 ) - direction = 1; -else - direction = 0; -z = 1.0; -while( x >= 3.0 ) - { - x -= 1.0; - z *= x; - } -/* -while( x < 0.0 ) - { - if( x > -1.E-4 ) - goto small; - z *=x; - x += 1.0; - } -*/ -while( x < 2.0 ) - { - if( x < 1.e-4 ) - goto small; - z *=x; - x += 1.0; - } - -if( direction ) - z = 1.0/z; - -if( x == 2.0 ) - return(z); - -x -= 2.0; -p = z * polevlf( x, P, 7 ); - -gdone: - -if( negative ) - { - p = sgngamf * PIF/(nz * p ); - } -return(p); - -small: -if( x == 0.0 ) - { - mtherr( "gamma", SING ); - return( MAXNUMF ); - } -else - { - p = z / ((1.0 + 0.5772156649015329 * x) * x); - goto gdone; - } -} - - - - -/* log gamma(x+2), -.5 < x < .5 */ -static float B[] = { - 6.055172732649237E-004, --1.311620815545743E-003, - 2.863437556468661E-003, --7.366775108654962E-003, - 2.058355474821512E-002, --6.735323259371034E-002, - 3.224669577325661E-001, - 4.227843421859038E-001 -}; - -/* log gamma(x+1), -.25 < x < .25 */ -static float C[] = { - 1.369488127325832E-001, --1.590086327657347E-001, - 1.692415923504637E-001, --2.067882815621965E-001, - 2.705806208275915E-001, --4.006931650563372E-001, - 8.224670749082976E-001, --5.772156501719101E-001 -}; - -/* log( sqrt( 2*pi ) ) */ -static float LS2PI = 0.91893853320467274178; -#define MAXLGM 2.035093e36 -static float PIINV = 0.318309886183790671538; - -/* Logarithm of gamma function */ - - -float lgamf( float xx ) -{ -float p, q, w, z, x; -float nx, tx; -int i, direction; - -sgngamf = 1; - -x = xx; -if( x < 0.0 ) - { - q = -x; - w = lgamf(q); /* note this modifies sgngam! */ - p = floorf(q); - if( p == q ) - goto loverf; - i = p; - if( (i & 1) == 0 ) - sgngamf = -1; - else - sgngamf = 1; - z = q - p; - if( z > 0.5 ) - { - p += 1.0; - z = p - q; - } - z = q * sinf( PIF * z ); - if( z == 0.0 ) - goto loverf; - z = -logf( PIINV*z ) - w; - return( z ); - } - -if( x < 6.5 ) - { - direction = 0; - z = 1.0; - tx = x; - nx = 0.0; - if( x >= 1.5 ) - { - while( tx > 2.5 ) - { - nx -= 1.0; - tx = x + nx; - z *=tx; - } - x += nx - 2.0; -iv1r5: - p = x * polevlf( x, B, 7 ); - goto cont; - } - if( x >= 1.25 ) - { - z *= x; - x -= 1.0; /* x + 1 - 2 */ - direction = 1; - goto iv1r5; - } - if( x >= 0.75 ) - { - x -= 1.0; - p = x * polevlf( x, C, 7 ); - q = 0.0; - goto contz; - } - while( tx < 1.5 ) - { - if( tx == 0.0 ) - goto loverf; - z *=tx; - nx += 1.0; - tx = x + nx; - } - direction = 1; - x += nx - 2.0; - p = x * polevlf( x, B, 7 ); - -cont: - if( z < 0.0 ) - { - sgngamf = -1; - z = -z; - } - else - { - sgngamf = 1; - } - q = logf(z); - if( direction ) - q = -q; -contz: - return( p + q ); - } - -if( x > MAXLGM ) - { -loverf: - mtherr( "lgamf", OVERFLOW ); - return( sgngamf * MAXNUMF ); - } - -/* Note, though an asymptotic formula could be used for x >= 3, - * there is cancellation error in the following if x < 6.5. */ -q = LS2PI - x; -q += ( x - 0.5 ) * logf(x); - -if( x <= 1.0e4 ) - { - z = 1.0/x; - p = z * z; - q += (( 6.789774945028216E-004 * p - - 2.769887652139868E-003 ) * p - + 8.333316229807355E-002 ) * z; - } -return( q ); -} |