home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
language
/
mjc2
/
mjclib
/
math.c
< prev
next >
Wrap
Text File
|
1988-03-31
|
6KB
|
345 lines
/* C library for MJC 2.0 - floating point and long arithmetic */
/*
* my floating point routines
*
* 32 bit floating point format
* bit function
* 31 sign
* 24-30 exponent (excess 64)
* 0-23 fraction
*/
#define NULL 0L
#define EXCESS 64
#define DIGITS 24
#define MAXFRAC 0xFFFFFF
#define MAXEXP 0x7F
#define MAXBITS 32
#define sign(x) ((x >> 31) & 1)
#define exp(x) (((x >> 24) & MAXEXP) - EXCESS)
#define frac(x) (x & MAXFRAC)
#define negate(x) (x ^ 0x80000000L)
/* long to float */
long
_ltof(n) long n; {
int s;
long _fnorm();
if (s = (n < 0L)) n = -n;
return _fnorm(s, DIGITS, n);
}
/* float to long */
long
_ftol(u) long u; {
int e, s;
long f;
s = sign(u);
e = exp(u);
f = frac(u);
if (e <= 0) { /* no fractional part */
return 0L;
}
else if (e < DIGITS) {
f = f >> (DIGITS - e);
}
else if (e == DIGITS) {
/* already there! */
}
else if (e < MAXBITS) {
f = f << (e - DIGITS);
}
else {
_ferr("ftol overflow\n\r");
f = 0x7FFFFFFF;
}
return s ? -f : f;
}
long
_fcmp(x, y) long x, y; {
return (sign(x) && sign(y)) ? y - x : x - y;
}
long
_fneg(x) long x; {
return negate(x);
}
long
_fsub(u, v) long u, v; {
long _fadd();
return _fadd(u, negate(v));
}
long
_fadd(u, v) long u, v; {
int t, sw, eu, ev, ew;
long fu, fv, fw, _fnorm();
if (u == 0L) return v;
if (v == 0L) return u;
eu = exp(u);
ev = exp(v);
fu = sign(u) ? -frac(u) : frac(u);
fv = sign(v) ? -frac(v) : frac(v);
t = eu - ev;
if (t <= -DIGITS) { /* u << v */
fw = fv;
ew = ev;
}
else if (t <= 0) { /* u <= v */
if (t) fu >>= -t;
fw = fv + fu;
ew = ev;
}
else if (t < DIGITS) { /* u > v */
fv >>= t;
fw = fv + fu;
ew = eu;
}
else { /* u >> v */
fw = fu;
ew = eu;
}
if (sw = (fw < 0))
fw = -fw;
return _fnorm(sw, ew, fw);
}
long
_fmul(u, v) long u, v; {
int sw, ew, eu, ev;
long fu, fv, fw, _fnorm();
if ((fu = frac(u)) == 0)
return 0L;
if ((fv = frac(v)) == 0)
return 0L;
eu = exp(u);
ev = exp(v);
sw = sign(u) ^ sign(v);
ew = eu + ev - 8;
fw = (fu >> 8) * (fv >> 8);
return _fnorm(sw, ew, fw);
}
long
_fdiv(u, v) long u, v; {
int sw, ew;
long _fnorm();
long b, fu, fv, fw;
if ((fu = frac(u)) == 0)
return 0L;
if ((fv = frac(v)) == 0)
return 0L;
sw = sign(u) ^ sign(v);
ew = exp(u) - exp(v) + 1;
fw = 0L;
b = 1L << (DIGITS - 1);
while (b) {
if (fu >= fv) {
fw += b;
fu -= fv;
}
b >>= 1;
fv >>= 1;
}
return _fnorm(sw, ew, fw);
}
/* ascii to float, needs no other support routines */
long
atof(s) char *s; {
int e, i, c, sgn;
unsigned long ipart, fpart, f, bit, div;
long _fnorm();
/* get to the start of the digits */
while (*s && *s <= ' ')
s++;
if ((sgn = (*s == '-')) || *s == '+')
s++;
/* get the integer and fraction parts */
ipart = 0L;
while (*s >= '0' && *s <= '9')
ipart = ipart * 10L + (*s++ - '0');
fpart = 0L;
if (*s == '.') {
s++;
/* 9 digits of precision please */
for (i = 0; i < 9; i++) {
if (*s >= '0' && *s <= '9')
c = *s++ - '0';
else c = 0;
fpart = fpart * 10L + c;
}
div = 500000000;
}
/* normalize the integer part, then work in the fraction */
if (ipart) {
f = _fnorm(sgn, DIGITS, ipart);
e = exp(f);
}
else e = f = 0L;
if (fpart && e < DIGITS) { /* room for the fraction part */
f = frac(f);
bit = 1L << (DIGITS - 1 - e);
/* add the fraction's bits to f */
while (bit && fpart) {
if (fpart >= div) {
fpart -= div;
f |= bit;
}
bit >>= 1;
div >>= 1;
}
if (fpart) f++; /* round up */
f = _fnorm(sgn, e, f);
}
/* now handle an exponent factor, if any */
if (f && (*s == 'e' || *s == 'E')) {
i = 0;
s++;
if ((c = (*s == '-')) || *s == '+')
s++;
for (i = 0; *s >= '0' && *s <= '9'; s++)
i = i * 10 + (*s - '0');
if (c) i = -i;
while (i > 0) {
e = exp(f);
f = frac(f);
f = _fnorm(sgn, e, f * 10L);
i--;
}
while (i < 0) {
e = exp(f);
f = frac(f);
f = _fnorm(sgn, e, f / 10L);
i++;
}
}
return f;
}
long
_fnorm(s, e, f) int s, e; unsigned long f; {
if (f == 0) {
return 0L;
}
else {
while (f & 0xFF000000L) {
f = (f >> 1) + (f & 1);
e++;
}
while ((f & 0x800000L) == 0) {
f = f << 1;
e--;
}
}
if (e >= EXCESS) {
_ferr("float overflow\n\r");
return ((long)s << 31) | 0x7FFFFFFFL;
}
else if (e < -EXCESS) {
_ferr("float underflow\n\r");
return 0L;
}
/* pack the result */
return ((long)s << 31) |
(((long)(e + EXCESS) & MAXEXP) << DIGITS) |
(f & MAXFRAC);
}
_ferr(s) char *s; { while (*s) trap(1, 2, *s++); }
/*
* stuff for long binary ops (both signed and unsigned)
* a and b are the left and right arguments to the binary operator
*
* div and mod are done by long division, shift b up until >= a, then
* back down, subtracting when appropriate
*
* mul is done by shifts and adds
*/
long
_lmul(a, b) long a, b; {
int neg = 0;
long _ulmul();
if (a < 0L) { neg++; a = -a; }
if (b < 0L) { neg++; b = -b; }
a = _ulmul(a, b);
return neg & 1 ? -a : a;
}
long
_ldiv(a, b) long a, b; {
int neg = 0;
long _ldivmod();
if (a < 0L) { neg++; a = -a; }
if (b < 0L) { neg++; b = -b; }
a = _ldivmod(a, b, 0);
return neg & 1 ? -a : a;
}
long
_lmod(a, b) long a, b; {
long _ldivmod();
if (a < 0L) a = -a;
if (b < 0L) b = -b;
return _ldivmod(a, b, 1);
}
long
_ulmul(a, b) unsigned long a, b; {
long result;
result = 0L;
while (a) {
if (a & 1L)
result += b;
a >>= 1L;
b <<= 1L;
}
return result;
}
long
_uldiv(a, b) long a, b; {
long _ldivmod();
return _ldivmod(a, b, 0);
}
long
_ulmod(a, b) long a, b; {
long _ldivmod();
return _ldivmod(a, b, 1);
}
long
_ldivmod(a, b, rem) unsigned long a, b; int rem; {
int i = 0;
unsigned long result = 0L;
if (b) {
while ((a > b) && !(b & 0x80000000L)) {
i++;
b <<= 1L;
}
while (1) {
if (a >= b) {
a -= b;
result++;
}
if (i == 0) break;
i--;
result <<= 1L;
b >>= 1L;
}
return rem ? a : result;
}
else i/0; /* should case a "divide zero" trap */
}