home *** CD-ROM | disk | FTP | other *** search
-
- /*
-
- 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
-