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.
-
- Only one version of each function is defined by this library.
- Whether error checking is done is determined by how this file
- is compiled. Error checking is ENABLED when the following
- #define is COMMENTED OUT.
-
- */
-
- /*#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;
-
- static short _Max[] = { 0x7FFE, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF };
- static short _MinusMax[] = { 0xFFFE, 0x7FFF, 0xFFFF, 0xFFFF, 0xFFFF };
- #define Max (* (double *) _Max)
- #define MinusMax (* (double *) _MinusMax)
-
- /* 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_
-
- /* ---------- environment ---------- */
-
-
- /*
- * 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);
- }
-
-
- /*
- * acos - inverse circular cosine
- *
- */
-
- double acos(x)
- double x;
- {
- DomainCheck(x > One || x < MinusOne, Zero);
- if (x == MinusOne)
- return(Pi);
- return(Two * atan(sqrt((One - x) / (One + x))));
- }
-
-
- /*
- * asin - inverse circular sine
- *
- */
-
- 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)));
- }
-
-
- /*
- * atan - inverse circular tangent
- *
- */
-
- double atan(x)
- double x;
- {
- elems68k(&x, FOATANX);
- return(x);
- }
-
-
- /*
- * atan2 - inverse circular tangent (y/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);
- }
-
-
- /*
- * ceil - round up to an integer
- *
- */
-
- double ceil(x)
- double x;
- {
- int state = SetRound(ROUND_UP);
- fp68k(&x, FORTI);
- SetState(state);
- return(x);
- }
-
-
- /*
- * cos - circular cosine
- *
- */
-
- double cos(x)
- double x;
- {
- elems68k(&x, FOCOSX);
- return(x);
- }
-
-
- /*
- * cosh - hyperbolic cosine
- *
- */
-
- double cosh(x)
- double x;
- {
- ClearExceptions();
- x = PointFive * exp(fabs(x));
- x += PointTwoFive / x;
- RangeCheck(x);
- return(x);
- }
-
-
- /*
- * exp - exponential function
- *
- */
-
- double exp(x)
- double x;
- {
- ClearExceptions();
- elems68k(&x, FOEXPX);
- RangeCheck(x);
- return(x);
- }
-
-
- /*
- * fabs - absolute value of a floating number
- *
- */
-
- double fabs(x)
- double x;
- {
- fp68k(&x, FOABS);
- return(x);
- }
-
-
- /*
- * floor - round down to an integer
- *
- */
-
- double floor(x)
- double x;
- {
- int state = SetRound(ROUND_DOWN);
-
- fp68k(&x, FORTI);
- SetState(state);
- return(x);
- }
-
-
- /*
- * fmod - remainder function
- *
- * This computes a value z, with the same sign as x, such that for some
- * integer k, k*y + z == x.
- *
- */
-
- double fmod(x, y)
- double x, y;
- {
- double z = x;
-
- fp68k(&y, FOABS);
- fp68k(&y, &z, FOREM);
-
- if (x > 0 && z < 0)
- z += y;
- else if (x < 0 && z > 0)
- z -= y;
- return(z);
- }
-
-
- /*
- * frexp - split floating number into fraction/exponent
- *
- * This computes a value z, where 0.5 <= fabs(z) < 1.0, and an integer n such
- * that z*(2^n) == x.
- *
- */
-
- double frexp(x, nptr)
- double x;
- register int *nptr;
- {
- double y = fabs(x), z = Two;
-
- if (y == 0) {
- *nptr = 0;
- return(Zero);
- }
-
- elems68k(&y, FOLOG2X);
-
- y -= *nptr = y;
-
- elems68k(&y, &z, FOPWRY);
-
- if (z >= One) {
- z *= PointFive;
- ++*nptr;
- }
- else if (z < PointFive) {
- z += z;
- --*nptr;
- }
- xfersign(x, &z);
- return(z);
- }
-
-
- /*
- * labs - absolute value of a long integer
- *
- */
-
- long labs(x)
- long x;
- {
- return(x < 0 ? -x : x);
- }
-
-
- /*
- * ldexp - combine fraction/exponent into a floating number
- *
- */
-
- double ldexp(x, n)
- double x;
- int n;
- {
- fp68k(&n, &x, FOSCALB);
- return(x);
- }
-
-
- /*
- * log - natural logarithm
- *
- */
-
- double log(x)
- double x;
- {
- DomainCheck(x <= 0, MinusMax);
- elems68k(&x, FOLNX);
- return(x);
- }
-
-
- /*
- * log10 - logarithm base 10
- *
- */
-
- double log10(x)
- double x;
- {
- DomainCheck(x <= 0, MinusMax);
- elems68k(&x, FOLOG2X); /* LOG2 is much faster than LN */
- return(x / Log2Ten);
- }
-
-
- /*
- * modf - split a floating number into fraction/integer
- *
- */
-
- double modf(x, nptr)
- double x;
- register double *nptr;
- {
- *nptr = x;
- fp68k(nptr, FOTTI);
- return(x - *nptr);
- }
-
-
- /*
- * pow - power function (exponentiation)
- *
- */
-
- double pow(x, y)
- double x, y;
- {
- int odd = 0;
- double z;
-
- 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);
- }
- elems68k(&y, &x, FOPWRY);
-
- RangeCheck(x);
- return(odd ? -x : x);
- }
-
- /*
- * rand - pseudo-random number generator (ANSI C standard)
- *
- */
-
- int rand()
- {
- seed = seed * 1103515245 + 12345;
- asm {
- move.w seed,d0 ; high word of long
- andi.w #0x7FFF,d0 ; remove high bit
- }
- }
-
-
- /*
- * sin - circular sine
- *
- */
-
- double sin(x)
- double x;
- {
- elems68k(&x, FOSINX);
- return(x);
- }
-
-
- /*
- * sinh - hyperbolic sine
- *
- */
-
- double sinh(x)
- double x;
- {
- double y = fabs(x);
-
- ClearExceptions();
- elems68k(&y, FOEXP1X);
- y += y / (y + One);
- y *= PointFive;
- RangeCheck(y);
- xfersign(x, &y);
- return(y);
- }
-
-
- /*
- * sqrt - square root
- *
- */
-
- double sqrt(x)
- double x;
- {
- DomainCheck(x < 0, Zero);
- fp68k(&x, FOSQRT);
- return(x);
- }
-
-
- /*
- * srand - seed pseudo-random number generator
- *
- */
-
- void srand(n)
- unsigned n;
- {
- seed = n;
- }
-
-
- /*
- * tan - circular tangent
- *
- */
-
- double tan(x)
- double x;
- {
- ClearExceptions();
- elems68k(&x, FOTANX);
- RangeCheck(x);
- return(x);
- }
-
-
- /*
- * tanh - hyperbolic tangent
- *
- */
-
- double tanh(x)
- double x;
- {
- double y = MinusTwo * fabs(x);
- elems68k(&y, FOEXP1X);
- y = -y / (y + Two);
- xfersign(x, &y);
- return(y);
- }
-