/************************************************************************ * * * A replacement exp() routine for PML library. An original algorithm * * is not changed but a table of fractionals power of 2 was recalcul- * * ated (believe it or not - this has an influence on a final result). * * Also divisions by power of 2 were replaced by applications of ldexp * * routine which is faster and better preserves precision * * * * Michal Jaegermann, December 1990 * * * ************************************************************************ */ /************************************************************************ * * * N O T I C E * * * * Copyright Abandoned, 1987, Fred Fish * * * * This previously copyrighted work has been placed into the * * public domain by the author (Fred Fish) and may be freely used * * for any purpose, private or commercial. I would appreciate * * it, as a courtesy, if this notice is left in all copies and * * derivative works. Thank you, and enjoy... * * * * The author makes no warranty of any kind with respect to this * * product and explicitly disclaims any implied warranties of * * merchantability or fitness for any particular purpose. * * * ************************************************************************ */ /* * FUNCTION * * exp double precision exponential * * KEY WORDS * * exp * machine independent routines * math libraries * * DESCRIPTION * * Returns double precision exponential of double precision * floating point number. * * USAGE * * double exp (x) * double x; * * REFERENCES * * Fortran IV plus user's guide, Digital Equipment Corp. pp B-3 * * Computer Approximations, J.F. Hart et al, John Wiley & Sons, * 1968, pp. 96-104. * * RESTRICTIONS * * Inputs greater than log(MAXDOUBLE) result in overflow. * Inputs less than log(MINDOUBLE) result in underflow. * * The maximum relative error for the approximating polynomial * is 10**(-16.4). However, this assumes exact arithmetic * in the polynomial evaluation. Additional rounding and * truncation errors may occur as the argument is reduced * to the range over which the polynomial approximation * is valid, and as the polynomial is evaluated using * finite precision arithmetic. * * PROGRAMMER * * Fred Fish * * INTERNALS * * Computes exponential from: * * exp(x) = 2**y * 2**z * 2**w * * Where: * * y = int ( x * log2(e) ) * * v = 16 * frac ( x * log2(e)) * * z = (1/16) * int (v) * * w = (1/16) * frac (v) * * Note that: * * 0 =< v < 16 * * z = {0, 1/16, 2/16, ...15/16} * * 0 =< w < 1/16 * * Then: * * 2**z is looked up in a table of 2**0, 2**1/16, ... * * 2**w is computed from an approximation: * * 2**w = (A + B) / (A - B) * * A = C + (D * w * w) * * B = w * (E + (F * w * w)) * * C = 20.8137711965230361973 * * D = 1.0 * * E = 7.2135034108448192083 * * F = 0.057761135831801928 * * Coefficients are from HART, table #1121, pg 206. * * Effective multiplication by 2**y is done by a * floating point scale with y as scale argument. * */ #include #include #include "pml.h" # define C 20.8137711965230361973 /* Polynomial approx coeff. */ /* # define D 1.0 */ /* Polynomial approx coeff. */ # define E 7.2135034108448192083 /* Polynomial approx coeff. */ # define F 0.057761135831801928 /* Polynomial approx coeff. */ /************************************************************************ * * * This table is fixed in size and reasonably hardware * * independent. The given constants were computed on Atari ST * * using integer arithmetic and decimal values for 2**(1/2), * * 2**(1/4) and 2**(1/8) taken from Appendix C of HART et al. * * * ************************************************************************ */ static double fpof2tbl[] = { 1.0/*0000000000000000000*/, /* 2 ** 0/16 */ 1.04427378242741384032, /* 2 ** 1/16 */ 1.09050773266525765920, /* 2 ** 2/16 */ 1.13878863475669165369, /* 2 ** 3/16 */ 1.18920711500272106671, /* 2 ** 4/16 */ 1.24185781207348404858, /* 2 ** 5/16 */ 1.29683955465100966592, /* 2 ** 6/16 */ 1.35425554693689272828, /* 2 ** 7/16 */ 1.41421356237309504880, /* 2 ** 8/16 */ 1.47682614593949931138, /* 2 ** 9/16 */ 1.54221082540794082360, /* 2 ** 10/16 */ 1.61049033194925430816, /* 2 ** 11/16 */ 1.68179283050742908605, /* 2 ** 12/16 */ 1.75625216037329948310, /* 2 ** 13/16 */ 1.83400808640934246346, /* 2 ** 14/16 */ 1.91520656139714729384 /* 2 ** 15/16 */ }; static char funcname[] = "exp"; double exp (x) double x; { register int index; auto int y; auto double w; auto double a; auto double b; auto double temp; auto char * xcptstr; extern double dabs (); extern double ldexp (); extern double modf (); auto struct exception xcpt; DBUG_ENTER (funcname); DBUG_3 ("expin", "arg %le", x); if (x > LOGE_MAXDOUBLE) { xcpt.type = OVERFLOW; xcpt.retval = MAXDOUBLE; xcptstr = "OVER"; goto eset; } if (x <= LOGE_MINDOUBLE) { xcpt.type = UNDERFLOW; xcpt.retval = 0.0; xcptstr = "UNDER"; eset: xcpt.name = funcname; xcpt.arg1 = x; if (!matherr (&xcpt)) { errno = ERANGE; fprintf (stderr, "%s: %sFLOW error\n", funcname, xcptstr); } } else { x *= LOG2E; w = ldexp(modf(x,&a), 4); y = a; w = ldexp(modf(w, &temp), -4); index = temp; b = w * w; a = C + b; b = w * (E + (F * b)); xcpt.retval = ldexp (((a + b) / (a - b)) * (index < 0 ? ldexp(fpof2tbl[16 + index], -1) : fpof2tbl[index]), y); } DBUG_3 ("expout", "result %le", xcpt.retval); DBUG_RETURN (xcpt.retval); }