home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel Volume 2 #1
/
carousel.iso
/
mactosh
/
lang
/
thinkc30.sit
/
Math.c
< prev
next >
Wrap
Text File
|
1989-01-16
|
8KB
|
613 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.
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);
}