Introduction
------------
The files in this directory consist of assembler and C source for an 
alternative maths library for Unices (including Xenix) running on an
80386/80387 combination and using gcc/gas as the compiler system. These
routines are typically from 2 to 10 times faster than those in the 
supplied maths library; assuming that your library, like mine 
(ESIX rev. D and Xenix 2.3.2), does not use the '387 inbuilts to perform 
transcendental calculations.

For those of you without a '387 you must use the full emulator and
consequently may not see any speed up. I haven't tried. Under Xenix you
must have a '387---some of the '387 instructions are not emulated. If you
have a '287 your in the same boat; some of the assembler routines won't
work.

I have coded the additional IEEE 754 required functions to provide a
conforming double precision implementation. 

You require gcc/gas in order to compile the assembler source code.

People who are using SUN 386i's (Roadrunner) may also find this useful.

I have found that writing good low level numerical code is far harder
than I initially thought it would be. But I've learnt a lot, and I still 
enjoy doing it.

Comments
--------
The additional program paranoia.c attempts to tell how well your floating
point conforms to the IEEE standard. You may like to compare the output
when linked with your existing library and with this one. Paranoia cannot be
compiled using standard 'cc' on Esix 3.2 revision D.

The file d2dcomb.summ contains a summary of some test results. See that
file for details.

The IEEE specified functions with which you may not be familiar are:

double copysign(x,y)
double x,y;
copysign returns x with the sign of y. IEEE denormal will be set if x is a
denormal.

double drem(x)
double x;
drem returns the IEEE remainder of x/y - it may be slow.

int finite(x)
double x;
finite returns true if -inf < x < inf; false otherwise. Does not raise any
floating point exceptions.

double logb(x)
double x;
logb returns the unbiased exponent of its argument.

double rint(x)
double x;
rint returns its argument rounded in the prevailing rounding mode.

double scalb(x, n)
double x;
int n;
scalb returns x*2^n.

Most of the above are just hooks directly into functions provided as single
instructions in the 80387.

double infinity()
infinity returns +inf. No exceptions are raised.

int isnan(x)
double x;
isnan returns 1 if x is a nan; 0 otherwise. Ieee exceptions are not
affected.

int isnormal(x)
double x;
isnormal returns 1 if x is a normalized number; 0 otherwise. Ieee exceptions 
are not affected.

int issubnormal(x)
double x;
issubnormal returns 1 if x is not a normalized number; 0 otherwise. Ieee 
exceptions are not affected.

int iszero(x)
double x;
iszero returns 1 if x is +/- 0.0; 0 otherwise. Ieee exceptions are not affected.

int isinf(x)
double x;
isinf returns 1 if x is +/- inf; 0 otherwise. Ieee exceptions are not affected.

int signbit(x)
double x;
signbit return the sign of x. 1 if negative and 0 if positive. Ieee
exceptions are not affected.

The is... functions and signbit are in the file ieee_ext.s

void ieee_retrospective(f)
FILE *f;
ieee_retrospective prints a list of IEEE exceptions that are currently
active on the 80387 in the file pointed to by f.

double
max_normal()
max_normal returns the maximum +ve normalized number. No exceptions are
raised.

double
min_normal()
mmin_normal returns the minimum +ve normalized number. No exceptions are
raised.

double
max_subnormal()
max_subnormal returns the largest +ve denormalized number. This raises the
denormal exception because of the way floating point numbers are returned.

double
min_subnormal()
min_subnormal returns the minimum +ve denormalized number. This raises the
denormal exception because of the way floating point numbers are returned.

double
quiet_nan(n)
long n;
quiet_nan returns a quiet nan. The argument is ignored. No exceptions are
raised.

double
signaling_nan(n)
long n;
signaling_nan returns a signaling nan. The argument is ignored. This raises
the invalid operation exception because of the way floating point numbers
are returned.

double
nextafter(x,y)
double x,y;
nextafter returns the next representable floating point number from x in
the direction of y. Exceptions may be raised depending on the arguments.

double erfcx(x)
double x;
erfcx returns x^2 * erfc(x).

Additional Functions
--------------------
It is suggested in the book `Programming the 80386' by Crawford and Gelsinger
that all floating point exceptions except `invalid operation' be masked. 
That is the 80387's inbuilt exception handler should be used. If you want this 
behaviour call setinternal() at the start of your code. This function is defined
by:

int setinternal()

and is declared for your convenience in fpumath.h. The return value is the
current control word. 

You can set the control word using setcont(mode). Again, this is defined in
fpumath.h:

int setcont(mode)
int mode;

This is really only provided to reset the original mode obtained using 
setinternal(). The previous mode is returned.

Note that more general forms of these functions are provided in the standard 
library using the fpsetmask and fpgetmask routines.

If you use setinternal(), arithmetic operations like 1/0 will return
infinity - inf will be printed if you are printing the output. Note that 0/0 
will still produce a floating point exception; the value of this operation 
is undefined.

double sqrtp(x)
double x;
Returns the sqrt of x in 64 bit (double) mode irrespective of the current
precision.

Acknowledgements
----------------
I'd like to thank the developers of the Berkeley Software Distribution who
believe in software freedom and made my job easier by providing C source
for all the functions. I also thank the author of paranoia.c. And also Dan Lau
of Intel. Also thanks go to W.J. Cody of Argonne National Laboratory
(USA).

And to everybody who has sent me feedback.


I have decided to cover the parts I wrote by the GNU General Public Licence 
with my modification (see below), a copy of which is included with this 
distribution.

In a nutshell, the Berkeley code is covered by their licence. My code is covered
by GNU's with my modification (see below). This infringes on nobodies rights.

Amendment to the GNU General Public Licence (*ONLY* applicable to my code)
-------------------------------------------
I may choose to cover this code by the Free Software Foundation's General
Public Library Licence when it becomes available. At present I make the 
following amendment to the licencing agreement:

*******************************************************************************
You may use this library in products which are distributed in binary format
only as long as you provide source code for the library with the distribution
or will supply the source code for the library for a period of 3 years from the
date of providing the binary files.
********************************************************************************

This in no way changes the GNU licence as applicable to other programs.

Also I have not modified the GPL it is ditributed in its original form as
it must be.

