Thread View: comp.unix.microport
1 messages
1 total messages
Started by Paul-Andre Panon for Jonathan Th...
Wed, 02 May 1990 19:04
bug in log(3) in Microport System V/AT 2.3.0-U
Author: Paul-Andre Panon for Jonathan Th...
Date: Wed, 02 May 1990 19:04
Date: Wed, 02 May 1990 19:04
199 lines
7562 bytes
7562 bytes
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@mtsg.ubc.ca
* Vancouver BC V6T 1W5 userbkis@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@mtsg.ubc.ca
Vancouver BC V6T 1W5 userbkis@ubcmtsg.bitnet
Canada ...!ubc-vision!ubcmtsg.bitnet!thornburg
--
Paul-Andre_Panon@staff.ucs.ubc.ca or USERPAP1@UBCMTSG
or Paul-Andre_Panon@undergrad.cs.ubc.ca or USERPAP1@mtsg.ubc.ca
Looking for a .signature? "We've already got one. It is ver-ry ni-sce!"
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads