/* exp.c * * Exponential function * * * * SYNOPSIS: * * float x, y, exp(); * * y = exp( x ); * * * * DESCRIPTION: * * Returns e (2.71828...) raised to the x power. * * Range reduction is accomplished by separating the argument * into an integer k and fraction f such that * * x k f * e = 2 e. * * A polynomial is used to approximate exp(f) * in the basic range [-0.5, 0.5]. * * * ACCURACY: * * Relative error: * arithmetic domain # trials peak rms * IEEE +- MAXLOG 100000 1.7e-7 2.8e-8 * * * Error amplification in the exponential function can be * a serious matter. The error propagation involves * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ), * which shows that a 1 lsb error in representing X produces * a relative error of X times 1 lsb in the function. * While the routine gives an accurate result for arguments * that are exactly represented by a double precision * computer number, the result contains amplified roundoff * error for large arguments not exactly represented. * * * ERROR MESSAGES: * * message condition value returned * exp underflow x < MINLOGF 0.0 * exp overflow x > MAXLOGF MAXNUMF * */ /* Cephes Math Library Release 2.2: June, 1992 Copyright 1984, 1987, 1989 by Stephen L. Moshier Direct inquiries to 30 Frost Street, Cambridge, MA 02140 */ /* Single precision exponential function. * test interval: [-0.5, +0.5] * trials: 80000 * peak relative error: 7.6e-8 * rms relative error: 2.8e-8 */ #include "mconf.h" extern float LOG2EF, MAXLOGF, MINLOGF, MAXNUMF; static float C1 = 0.693359375; static float C2 = -2.12194440e-4; #ifdef ANSIC float floor( float ), ldexp( float, int ); float exp( float xx ) #else float floor(); float ldexp(); float exp(xx) double xx; #endif { float x, z; int n; x = xx; if( x > MAXLOGF) { mtherr( "exp", OVERFLOW ); return( MAXNUMF ); } if( x < MINLOGF ) { mtherr( "exp", UNDERFLOW ); return(0.0f); } /* Express e**x = e**g 2**n * = e**g e**( n loge(2) ) * = e**( g + n loge(2) ) */ z = floor( LOG2EF * x + 0.5f ); /* floor() truncates toward -infinity. */ x -= z * C1; x -= z * C2; n = z; z = x * x; /* Theoretical peak relative error in [-0.5, +0.5] is 4.2e-9. */ z = ((((( 1.9875691500E-4f * x + 1.3981999507E-3f) * x + 8.3334519073E-3f) * x + 4.1665795894E-2f) * x + 1.6666665459E-1f) * x + 5.0000001201E-1f) * z + x + 1.0f; /* multiply by power of 2 */ x = ldexp( z, n ); return( x ); }