home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel Volume 2 #1
/
carousel.iso
/
mactosh
/
lang
/
lsc30p4u.sit
/
MathHybrid.c
< prev
next >
Wrap
Text File
|
1989-01-16
|
10KB
|
711 lines
/*
Math library for LightspeedC
(C) Copyright 1986 THINK Technologies. All rights reserved.
For details, refer to Harbison & Steele's "C: A Reference Manual",
Chapter 11.
Two versions of each function are defined by this library: an
error-checking version (e.g. "sin") and a non-error-checking
version (e.g. "_sin").
The non-underscore names can be made to refer to the non-error-
checking functions by #defining _NOERRORCHECK_ before #including
"math.h". Doing so in THIS file suppresses the definitions of
the error-checking versions of the functions altogether.
*/
/*#define _NOERRORCHECK_*/
#include "math.h"
#include "sane.h"
/* useful constants */
static double Zero = 0.0;
static double One = 1.0;
static double Two = 2.0;
static double MinusOne = -1.0;
static double MinusTwo = -2.0;
static double PointFive = 0.5;
static double PointTwoFive = 0.25;
static double Pi = PI;
static double Pi2 = PI2;
static double Log2Ten = 3.321928094887362348;
/* the 80-bit extended "_x80" is used as the destination to convert the
arguments to SANE doubles. */
static Extended80 _x80;
/* the extra word of zeros is for 68881 compatibility. */
static short _Max[] = { 0x7FFE, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF };
static short _MinusMax[] = { 0xFFFE, 0x0000, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF };
#define Max (* (double *) _Max)
#define MinusMax (* (double *) _MinusMax)
/* routines for conversion between 80- and 96-bit formats */
void x80tox96(x80, x96)
register Extended80 *x80;
register Extended96 *x96;
{
(*x96).exponent = (*x80).exponent;
(*x96).reserved = 0;
(*x96).mantissa = (*x80).mantissa;
}
void x96tox80(x96, x80)
register Extended96 *x96;
register Extended80 *x80;
{
(*x80).exponent = (*x96).exponent;
(*x80).mantissa = (*x96).mantissa;
}
#define _x80tox96(x80, x96) x80tox96(&x80, &x96)
#define _x96tox80(x96, x80) x96tox80(&x96, &x80)
#define _to80(x) _x96tox80(x, _x80);
#define _to96(x) _x80tox96(_x80, x);
/* seed for pseudo-random number generator */
static unsigned long seed = 1;
/* environment word masks */
#define ROUND 0x6000
#define ROUND_UP 0x2000
#define ROUND_DOWN 0x4000
#define ERROR 0x0F00
/* ---------- error checking ---------- */
#ifdef _ERRORCHECK_
#define DomainCheck(test, result) if (test) { \
errno = EDOM; \
return(result); \
}
#define RangeCheck(target) if (GetState() & ERROR) { \
errno = ERANGE; \
target = Max; \
}
#else _ERRORCHECK_
#define ClearExceptions()
#define DomainCheck(test, result)
#define RangeCheck(target)
#endif _ERRORCHECK_
/*
* GetState - query environment word
*
*/
static
GetState()
{
int state;
GetEnvironment(&state);
return(state);
}
/*
* SetState - define environment word
*
*/
static
SetState(state)
{
SetEnvironment(&state);
}
/*
* ClearExceptions - clear error conditions
*
* This must be called if RangeCheck is to be used.
*
*/
#ifdef _ERRORCHECK_
static
ClearExceptions()
{
int state;
GetEnvironment(&state);
state &= ~ERROR;
SetEnvironment(&state);
}
#endif _ERRORCHECK_
/*
* SetRound - define rounding direction
*
* The previous environment word is returned. The rounding direction can
* be restored by passing this value to SetState.
*
*/
static
SetRound(direction)
{
int state;
GetEnvironment(&state);
SetState((state & ~ROUND) | direction);
return(state);
}
/*
* xfersign - transfer sign from one floating number to another
*
*/
static
xfersign(x, yp)
double x, *yp;
{
asm {
movea.l yp,a0
bclr #7,(a0)
tst.w x
bpl.s @1
bset #7,(a0)
@1 }
}
/* ---------- math functions (alphabetically) ---------- */
/*
* abs - absolute value of an integer
*
*/
int abs(x)
int x;
{
return(x < 0 ? -x : x);
}
/* the real functions are here, in fact, when _ERRORCHECK_ is undefined,
they will be called directly.*/
/* some pre-declarations..*/
double _exp();
double _fabs();
double _acos(x)
double x;
{
return(Two * atan(sqrt((One - x) / (One + x))));
}
double _asin(x)
double x;
{
double y = _fabs(x);
DomainCheck(y > One, Zero);
if (y == One) {
y = Pi2;
xfersign(x, &y);
return(y);
}
if (y > PointFive) {
y = One - y;
y = Two * y - y * y;
}
else
y = One - y * y;
return(atan(x / sqrt(y)));
}
double _atan(x)
double x;
{
_to80(x);
elems68k(&_x80, FOATANX);
_to96(x);
return(x);
}
double _atan2(y, x)
double y, x;
{
double z;
if (x == 0) {
DomainCheck(y == 0, Zero);
z = Pi2;
}
else {
z = atan(fabs(y / x));
if (x < 0)
z = Pi - z;
}
xfersign(y, &z);
return(z);
}
double _ceil(x)
double x;
{
register int state = SetRound(ROUND_UP);
_to80(x);
fp68k(&_x80, FORTI);
SetState(state);
_to96(x);
return(x);
}
double _cos(x)
double x;
{
_to80(x)
elems68k(&_x80, FOCOSX);
_to96(x)
return(x);
}
double _cosh(x)
double x;
{
ClearExceptions();
x = PointFive * _exp(_fabs(x));
x += PointTwoFive / x;
RangeCheck(x);
return(x);
}
double _exp(x)
double x;
{
_to80(x);
elems68k(&_x80, FOEXPX);
_to96(x);
return(x);
}
double _fabs(x)
double x;
{
_to80(x);
fp68k(&_x80, FOABS);
_to96(x);
return(x);
}
double _floor(x)
double x;
{
register int state = SetRound(ROUND_DOWN);
_to80(x);
fp68k(&_x80, FORTI);
_to96(x);
SetState(state);
return(x);
}
double _fmod(x, y)
double x, y;
{
double z;
Extended80 tz;
_x96tox80(x, tz);
_to80(y);
fp68k(&_x80, FOABS);
fp68k(&_x80, &tz, FOREM);
_to96(y);
_x80tox96(tz, z);
if (x > 0 && z < 0)
z += y;
else if (x < 0 && z > 0)
z -= y;
return(z);
}
double _frexp(x, nptr)
double x;
register int *nptr;
{
double y = fabs(x), z = Two;
Extended80 ty, tz;
if (y == 0) {
*nptr = 0;
return(Zero);
}
_x96tox80(y, ty);
elems68k(&ty, FOLOG2X);
_x80tox96(ty, y);
y -= *nptr = y;
_x96tox80(y, ty);
_x96tox80(z, tz);
elems68k(&ty, &tz, FOPWRY);
_x80tox96(ty, y);
_x80tox96(tz, z);
if (z >= One) {
z *= PointFive;
++*nptr;
}
else if (z < PointFive) {
z += z;
--*nptr;
}
xfersign(x, &z);
return(z);
}
double _ldexp(x, n)
double x;
int n;
{
_to80(x);
fp68k(&n, &_x80, FOSCALB);
_to96(x);
return(x);
}
double _log(x)
double x;
{
_to80(x);
elems68k(&_x80, FOLNX);
_to96(x);
return(x);
}
double _log10(x)
double x;
{
_to80(x);
elems68k(&_x80, FOLOG2X); /* LOG2 is much faster than LN */
_to96(x);
return(x/ Log2Ten);
}
double _modf(x, nptr)
double x;
register double *nptr;
{
_to80(x);
fp68k(&_x80, FOTTI);
x80tox96(&_x80, nptr);
return(x - *nptr);
}
double _pow(x, y)
double x, y;
{
double tx, ty;
_x96tox80(y, ty);
_x96tox80(x, tx);
elems68k(&ty, &tx, FOPWRY);
/* _x80tox96(ty, y); */
_x80tox96(tx, x);
return(x);
}
double _sin(x)
double x;
{
_to80(x);
elems68k(&_x80, FOSINX);
_to96(x);
return(x);
}
double _sinh(x)
double x;
{
double y = _fabs(x);
_to80(y);
elems68k(&_x80, FOEXP1X);
_to96(y);
y += y / (y + One);
y *= PointFive;
xfersign(x, &y);
return(y);
}
double _sqrt(x)
double x;
{
_to80(x);
fp68k(&_x80, FOSQRT);
_to96(x);
return(x);
}
double _tan(x)
double x;
{
_to80(x);
elems68k(&_x80, FOTANX);
_to96(x);
return(x);
}
double _tanh(x)
double x;
{
double y = MinusTwo * _fabs(x);
_to80(y);
elems68k(&_x80, FOEXP1X);
_to96(y);
y = -y / (y + Two);
xfersign(x, &y);
return(y);
}
long labs(x)
long x;
{
return(x < 0 ? x: -x);
}
int rand()
{
seed = seed * 1103515245 + 12345;
asm {
move.w seed,d0 ; high word of long
andi.w #0x7FFF,d0 ; remove high bit
}
}
void srand(n)
unsigned n;
{
seed = n;
}
#ifdef _ERRORCHECK_
double acos(x)
double x;
{
DomainCheck(x > One || x < MinusOne, Zero);
if (x == MinusOne)
return(Pi);
return(_acos(x));
}
double asin(x)
double x;
{
return(_asin(x));
}
double atan(x)
double x;
{
return(_atan(x));
}
double atan2(y, x)
double y, x;
{
return(_atan2(y, x));
}
double ceil(x)
double x;
{
return(_ceil(x));
}
double cos(x)
double x;
{
return(_cos(x));
}
double cosh(x)
double x;
{
return(_cosh(x));
}
double exp(x)
double x;
{
ClearExceptions();
x = _exp(x);
RangeCheck(x);
return(x);
}
double fabs(x)
double x;
{
return(_fabs(x));
}
double floor(x)
double x;
{
return(_floor(x));
}
double fmod(x, y)
double x, y;
{
return(_fmod(x, y));
}
double frexp(x, nptr)
double x;
register int *nptr;
{
return(_frexp(x, nptr));
}
/*
* ldexp - combine fraction/exponent into a floating number
*
*/
double ldexp(x, n)
double x;
int n;
{
return(_ldexp(x, n));
}
double log(x)
double x;
{
DomainCheck(x <= 0, MinusMax);
return(_log(x));
}
double log10(x)
double x;
{
DomainCheck(x <= 0, MinusMax);
return(_log10(x));
}
double modf(x, nptr)
double x, *nptr;
{
return(_modf(x, nptr));
}
double pow(x, y)
double x, y;
{
int odd = 0;
Extended80 tx, ty;
ClearExceptions();
if (x == 0) {
if (y <= 0) {
#ifdef _ERRORCHECK_
errno = EDOM;
#endif
return (MinusMax);
}
return(Zero);
}
if (y == 0)
return(One);
if (x < 0) {
if (_modf(y, &y)) {
#ifdef _ERRORCHECK_
errno = EDOM;
#endif
return (MinusMax);
}
x = -x;
odd = _fmod(y, Two);
}
x = _pow(x, y);
RangeCheck(x);
return(odd ? -x : x);
}
double sin(x)
double x;
{
return(_sin(x));
}
double sinh(x)
double x;
{
double y;
ClearExceptions();
y = _sinh(x);
RangeCheck(y);
return(y);
}
double sqrt(x)
double x;
{
DomainCheck(x < 0, Zero);
return(_sqrt(x));
}
/*
* tan - circular tangent
*
*/
double tan(x)
double x;
{
ClearExceptions();
x = _tan(x);
RangeCheck(x);
return(x);
}
/*
* tanh - hyperbolic tangent
*
*/
double tanh(x)
double x;
{
return(_tanh(x));
}
#endif