Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
kcc-4/lib/math/log.c
There are 7 other files named log.c in the archive. Click here to see a list.
/*
* +++ NAME +++
*
* LOG Double precision natural log
*
* +++ INDEX +++
*
* LOG
* machine independent routines
* math libraries
*
* +++ DESCRIPTION +++
*
* Returns double precision natural log of double precision
* floating point argument.
*
* +++ USAGE +++
*
* double log(x)
* double x;
*
* +++ REFERENCES +++
*
* Computer Approximations, J.F. Hart et al, John Wiley & Sons,
* 1968, pp. 105-111.
*
* +++ RESTRICTIONS +++
*
* The absolute error in the approximating polynomial is
* 10**(-19.38). Note that contrary to DEC's assertion
* in the F4P user's guide, the error is absolute and not
* relative.
*
* This error bound 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
* Goodyear Aerospace Corp, Arizona Div.
* (602) 932-7000 work
* (602) 894-6881 home
*
* Updated Dec 85 for inclusion in standard math library. This routine
* now conforms with the description of the log function as defined in
* Harbison & Steele's "C: A Reference Manual", section 11.3.16
*
* +++ INTERNALS +++
*
* Computes log(X) from:
*
* (1) If argument is zero then flag an error
* and return minus infinity (or rather its
* machine representation).
*
* (2) If argument is negative then flag an
* error and return minus infinity.
*
* (3) Given that x = m * 2**k then extract
* mantissa m and exponent k.
*
* (4) Transform m which is in range [0.5,1.0]
* to range [1/sqrt(2), sqrt(2)] by:
*
* s = m * sqrt(2)
*
* (4) Compute z = (s - 1) / (s + 1)
*
* (5) Now use the approximation from HART
* page 111 to find ln(s):
*
* log(s) = z * ( P(z**2) / Q(z**2) )
*
* Where:
*
* P(z**2) = SUM [ Pj * (z**(2*j)) ]
* over j = {0,1,2,3}
*
* Q(z**2) = SUM [ Qj * (z**(2*j)) ]
* over j = {0,1,2,3}
*
* P0 = -0.240139179559210509868484e2
* P1 = 0.30957292821537650062264e2
* P2 = -0.96376909336868659324e1
* P3 = 0.4210873712179797145
* Q0 = -0.120069589779605254717525e2
* Q1 = 0.19480966070088973051623e2
* Q2 = -0.89111090279378312337e1
* Q3 = 1.0000
*
* (coefficients from HART table #2705 pg 229)
*
* Note: according to a message in the Unix
* USENET, the accuracy of the routine
* can be improved by changing the definition
* of P2 above to:
*
* P2 = -.963769093377840513e1;
*
* Submitted by Guido van Rossum,
* {philabs,decvax}!mcvax!guido
* Centre for Mathematics and Computer Science,
* Amsterdam
*
* (with thanks to Lambert Meertens)
*
* (5) Finally, compute log(x) from:
*
* log(x) = (k * log(2)) - log(sqrt(2)) + log(s)
*
* ---
*/
#include "math.h"
#include "errno.h"
static double log_pcoeffs[] = {
-0.24013917955921050986e2,
0.30957292821537650062e2,
#if 0
-0.96376909336868659324e1,
#else
-.963769093377840513e1, /* See note above */
#endif
0.4210873712179797145
};
static double log_qcoeffs[] = {
-0.12006958977960525471e2,
0.19480966070088973051e2,
-0.89111090279378312337e1,
1.0000
};
double log(x)
double x;
{
register int k;
double s, z, zt2, pqofz;
if (x <= 0.0) {
errno = EDOM;
return MAX_NEG_DBLF;
} else {
k = _xexp(x);
s = SQRT2 * _xmant(x);
z = (s - 1.0) / (s + 1.0);
zt2 = z * z;
pqofz = z * _poly(3, log_pcoeffs, zt2) / _poly(3, log_qcoeffs, zt2);
return (k * LN2) - LNSQRT2 + pqofz;
}
}