bug in log(3) in Microport System V/AT 2.3.0-U
Paul-Andre Panon for Jonathan Thornburg
panon at cheddar.cc.ubc.ca
Thu May 3 05:04:45 AEST 1990
I'm posting this for Jonathan Thornburg in our Astronomy dept. who seems
to have a read-only news connection.
---------------------------------
There's a bug in log(3) in Microport's System V/AT 2.3.0-U. This is on an
AT clone with no hardware floating point. The problem is that, for arguments
between 0.5 and 1.0, the answers are wrong. In particular, log(0.8) gives a
*positive* result!.
The (my) fix is to rewrite log(3). I'm not brave enough to change libm, so I
put my new log(3) in a new library, "libfixm"; I do "-lfixm -lm" whenever I
used to do "-lm". (Yes, this is a kludge...)
Here's the code for a new log(3) I cooked up:
---------- file "log.c" ----------
/* log - my log(), log10() functions for IEEE double precision floating pt.
*/
/*
** <<<useful constants>>>
* log10 - base 10 logarithm function (calls log())
* log - natural logarithm function
*/
#include <math.h>
#define then
#define EDOM DOMAIN /* from <math.h> */
/***************************************************************************
**/
/*
* This software written by
* Jonathan Thornburg
* Dept of Geophysics & Astronomy
* The University of British Columbia thornburg at mtsg.ubc.ca
* Vancouver BC V6T 1W5 userbkis at ubcmtsg.bitnet
* Canada ...!ubc-vision!ubcmtsg.bitnet!thornburg
* on 5 April 1990. It's in the public domain.
*
* The constants and coefficients are from
* John F. Hart, E. W. Cheney, Charles L. Lawson, Hans J. Maehly,
* Charles K. Mesztenyi, John R. Rice, Henry G. Thacher, Jr.,
* and Christoph Witzgall,
* "Computer Approximations",
* Krieger (1978)
*/
/* useful constants, from appendix C */
#define LOG10_OF_E 0.43429448190325182765
#define SQRT_OF_HALF 0.70710678118654752440
#define LOGE_OF_2 0.69314718055994530942
/***************************************************************************
**/
/*
* This is the base 10 logarithm function.
*/
public double log10(x)
double x;
{
public double log();
return( LOG10_OF_E * log(x) );
}
/***************************************************************************
**/
/*
* This is the natural logarithm function.
*
* The algorithm used is:
* 1. Check for domain error.
* 2. Range reduce to [1/2, 1).
* 3. Range adjust to [1/sqrt(2), sqrt(2))
* 4. Compute rational approximation on this range (#2704 in Hart et al).
* 5. Compute result.
*
* Bugs:
* - The System V matherr() error handling system is *not* supported. Instead,
* we return -HUGE (defined in <math.h> and set errno to EDOM (defined above)
* on a domain error (argument <= 0).
* - This function was put together in a hurry (when I found that my system's
* log() returns garbage for some arguments), with only minimal attention to
* minimizing cancellation and roundoff error. My rather limited tests of it
* have found no errors larger than 2 units in the least significant bit, but
* I don't guarantee this.
* - For the same reason, this function is somewhat slower (perhaps up to a
* factor of 2 on machines with software floating point) than necessary. It
* uses floating point throughout, where a "tuned" implementation could use
* fixed point. In stage 3, a more extensive range reduction might well be
* faster. In stage 4, an "economized" (eg Pan form, c.f. Hart or Knuth v.2)
* polynomial evaluation scheme might be faster. In stage 5, it does an
* integer to floating point conversion and a floating point multiplication
* where a "tuned" implementation could do a table lookup for most arguments.
*/
public double log(x)
double x;
{
double f, z, z2;
int n;
double P_of_z2, Q_of_z2, log_of_f;
double log_of_x;
static double P[] = {
-0.90174691662040536329e+02,
0.93463900642858538247e+02,
-0.18327870372215593212e+02
};
static double Q[] = {
-0.45087345831020305748e+02,
0.61761065598471302843e+02,
-0.20733487895513939345e+02,
1.0 /* not actually used */
};
/*
* Stage 1: Check for domain error
*/
if (x <= 0.0)
then {
errno = EDOM;
return(- HUGE);
}
/*
* Stage 2: Range reduce to [1/2, 1).
*
* We compute (f,n) such that x = f * 2**n.
*/
f = frexp(x, &n);
/*
* Stage 3: Range adjust to [1/sqrt(2), sqrt(2)).
*
* We maintain the invariant that x = f * 2**n.
*
* As mentioned under "Bugs:" in the function comments, it might be worthwhile
* doing a extensive range reduction, perhaps to [1/(2**.25), 2**.25). This
* would allow a lower-degree rational approximation to be used in stage 4.
*/
if (f < SQRT_OF_HALF)
then {
f = ldexp(f, 1);
--n;
}
/*
* Stage 4: Compute rational approximation to log(f) on [1/sqrt(2), sqrt(2)).
*
* The approximation is of the form
* log(f) = z * P(z^2) / Q(z^2)
* It's #2704 in the Hart et al reference given above (note the typo in the
* heading of the index listing).
*
* As mentioned under "Bugs:" in the function comments, it might be worthwhile
* using an "economized" polynomial evaluation technique (eg Pan form, c.f.
* Hart or Knuth v.2) here. Another possibility is to use the J-fraction form
* for the rational approximation.
*/
z = (f - 1.0) / (f + 1.0);
z2 = z * z;
P_of_z2 = P[0] + z2 * (P[1] + z2 * P[2]);
Q_of_z2 = Q[0] + z2 * (Q[1] + z2 * (Q[2] + z2 /* * Q[3] */));
log_of_f = z * P_of_z2 / Q_of_z2;
/*
* Stage 5: Compute result log(x).
*
* As mentioned under "Bugs:" in the function comments, we could replace the
* integer to floating point conversion and floating point multiply
* LOGE_OF_2 * ((double) n)
* by a table lookup of values of this expression. Since IEEE double precision
* floating point format has an exponent range of about +/- 1024, a table with
* entries for all possible exponents would be quite large (2K entries @ 8
* bytes = 16K bytes). Thus the best thing would probably be to have the table
* only cover (say) the IEEE single precison floating point exponent range of
* about +/- 128 (==> 1K bytes), and do the integer to floating point
* conversion and floating point multiply for the remaining (very large or very
* small) exponents.
*/
log_of_x = LOGE_OF_2 * ((double) n) + log_of_f;
return(log_of_x);
}
---------- end of file "log.c" ----------
- Jonathan Thornburg
Dept of Geophysics & Astronomy
The University of British Columbia thornburg at mtsg.ubc.ca
Vancouver BC V6T 1W5 userbkis at ubcmtsg.bitnet
Canada ...!ubc-vision!ubcmtsg.bitnet!thornburg
--
Paul-Andre_Panon at staff.ucs.ubc.ca or USERPAP1 at UBCMTSG
or Paul-Andre_Panon at undergrad.cs.ubc.ca or USERPAP1 at mtsg.ubc.ca
Looking for a .signature? "We've already got one. It is ver-ry ni-sce!"
More information about the Comp.unix.microport
mailing list