home *** CD-ROM | disk | FTP | other *** search
- /*
- * math.c logo math functions module dvb
- *
- * Copyright (C) 1993 by the Regents of the University of California
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
- #include "logo.h"
- #include "globals.h"
- #include <signal.h>
- #include <setjmp.h>
- #include <math.h>
-
- #define isdigit(dig) (dig >= '0' && dig <= '9')
-
- int numberp(NODE *snd) {
- int dl,dr, pcnt, plen;
- char *p;
-
- if (is_number(snd)) return(1);
-
- snd = cnv_node_to_strnode(snd);
- if (snd == UNBOUND) return(0);
-
- p = getstrptr(snd); plen = getstrlen(snd); pcnt = dl = dr = 0;
- if (plen >= MAX_NUMBER) {
- return(0);
- }
-
- if (pcnt < plen && *p == '-')
- p++, pcnt++;
-
- while (pcnt < plen && isdigit(*p))
- p++, pcnt++, dl++;
-
- if (pcnt < plen && *p == '.') {
- p++, pcnt++;
- while (pcnt < plen && isdigit(*p))
- p++, pcnt++, dr++;
- }
-
- if (pcnt < plen && (dl || dr) && (*p == 'E' || *p == 'e')) {
- p++, pcnt++;
-
- if (pcnt < plen && (*p == '+' || *p == '-'))
- p++, pcnt++;
-
- while (pcnt < plen && isdigit(*p))
- p++, pcnt++, dr++;
- }
-
- if ((dl == 0 && dr == 0) || pcnt != plen)
- return (0);
- else
- return (dr + 1);
- }
-
- NODE *lrandom(NODE *arg) {
- NODE *val;
- long r;
-
- val = pos_int_arg(arg);
- if (NOT_THROWING) {
- #ifdef HAVE_SRANDOM
- r = (getint(val) == 0 ? 0 : random() % getint(val));
- #else
- r = (((long)rand()) << 15) | rand();
- r = (getint(val) == 0 ? 0 : r % getint(val));
- #endif
- val = newnode(INT);
- #ifdef AMIGA
- if (r<0) r=-r;
- #endif
- setint(val, (FIXNUM)r);
- return(val);
- } else return(UNBOUND);
- }
-
- NODE *lrerandom(NODE *arg) {
- int seed=1;
-
- if (arg != NIL) {
- seed = int_arg(arg);
- }
- if (NOT_THROWING) {
- #ifdef HAVE_SRANDOM
- srandom((int)seed);
- #else
- srand((int)seed);
- #endif
- }
- return(UNBOUND);
- }
-
- jmp_buf oflo_buf;
- BOOLEAN handling_oflo = FALSE;
-
- #if defined(__ZTC__) || defined(WIN32)
- #define sig_arg 0
- void handle_oflo(int sig) {
- #else
- #define sig_arg
- RETSIGTYPE handle_oflo() {
- #endif
- signal(SIGFPE, handle_oflo);
- if (handling_oflo) longjmp(oflo_buf,1);
- }
-
- void math_init() {
- signal(SIGFPE, handle_oflo);
- }
-
- #ifdef HAVE_MATHERR
- int matherr(struct exception *x) {
- if (x->type == UNDERFLOW) return(1);
- longjmp(oflo_buf,1);
- }
- #endif
-
- #ifdef mac
- FLONUM degrad = 0.017453292520;
- #else
- FLONUM degrad = 3.141592653589793227020265931059839203954/180.0;
- #endif
-
- #if defined(mac)||defined(ibm)
- #define errchk(x) {errno = 0; x; if (errno) err_logo(BAD_DATA_UNREC,arg);}
- #include <errno.h>
- #else
- #define errchk(x) x
- #endif
-
- NODE *binary(NODE *args, char fcn) {
- NODE *arg, *val;
- BOOLEAN imode;
- FIXNUM iarg = 0, ival = 0, oval, nval;
- FLONUM farg = 0.0, fval = 0.0;
- int sign, wantint=0;
-
- /* Force imode, arg and fval into the stack because otherwise they may be
- clobbered during setjmp/longjmp. Especially on Sparc. */
- (void)&imode; (void)&arg; (void)&fval;
-
- if (fcn == '%' || fcn == 'm')
- arg = integer_arg(args);
- else
- arg = numeric_arg(args);
- args = cdr(args);
- if (stopping_flag == THROWING) return UNBOUND;
- if (nodetype(arg) == INT) {
- imode = TRUE;
- ival = getint(arg);
- } else {
- imode = FALSE;
- fval = getfloat(arg);
- }
- if (args == NIL) { /* one argument supplied */
- if (imode)
- switch(fcn) {
- case '-': ival = -ival; break;
- case '~': ival = ~ival; break;
- case 's':
- case 'c':
- case 't':
- case 'S':
- case 'C':
- case 'T':
- case 'q':
- case 'e':
- case 'g':
- case 'n':
- case '/':
- imode = FALSE;
- fval = (FLONUM)ival;
- break;
- }
- if (imode == FALSE) {
- if (!setjmp(oflo_buf)) {
- switch(fcn) {
- case '-': fval = -fval; break;
- case '/':
- if (fval == 0.0)
- err_logo(BAD_DATA_UNREC,arg);
- else
- fval = 1/fval;
- break;
- case '~': err_logo(BAD_DATA_UNREC,arg); break;
- case 'c':
- fval = 90.0 - fval;
- case 's':
- /* Kahan sez we can't just multiply any old
- * angle by degrad, but have to get into the
- * range 0-45 first */
- sign = (fval < 0.0);
- if (sign) fval = -fval;
- #ifndef HAVE_DREM
- fval = fmod(fval,360.0);
- #else
- fval = drem(fval,360.0);
- #endif
- if (fval > 180.0) {
- fval -= 180.0;
- sign = !sign;
- }
- if (fval > 90.0) fval = 180.0 - fval;
- if (fval > 45.0)
- fval = cos((90.0-fval)*degrad);
- else
- fval = sin(fval*degrad);
- if (sign) fval = -fval;
- break;
- case 't': fval = atan(fval)/degrad; break;
- case 'S': fval = sin(fval); break;
- case 'C': fval = cos(fval); break;
- case 'T': fval = atan(fval); break;
- case 'q': errchk(fval = sqrt(fval)); break;
- case 'e': errchk(fval = exp(fval)); break;
- case 'g': errchk(fval = log10(fval)); break;
- case 'n': errchk(fval = log(fval)); break;
- case 'r':
- fval += (fval < 0 ? -0.5 : 0.5);
- case 'i':
- handling_oflo = TRUE;
- if (fval > (FLONUM)MAXLOGOINT ||
- fval < -(FLONUM)MAXLOGOINT)
- handle_oflo(sig_arg);
- ival = (FIXNUM)fval;
- imode = TRUE;
- handling_oflo = FALSE;
- break;
- }
- } else { /* overflow */
- if (fcn == 'r' || fcn == 'i') {
- if (fval < 0.0)
- fval = ceil(fval);
- else
- fval = floor(fval);
- } else
- err_logo(BAD_DATA_UNREC,arg);
- }
- } /* end float case */
- } /* end monadic */
- while (args != NIL && NOT_THROWING) {
- if (fcn == '%' || fcn == 'm')
- arg = integer_arg(args);
- else
- arg = numeric_arg(args);
- args = cdr(args);
- if (stopping_flag == THROWING) return UNBOUND;
-
- if (nodetype(arg) == INT) {
- if (imode) iarg = getint(arg);
- else farg = (FLONUM)getint(arg);
- } else {
- if (imode) {
- fval = (FLONUM)ival;
- imode = FALSE;
- }
- farg = getfloat(arg);
- }
-
- if (imode) {
- oval = ival;
- handling_oflo = TRUE;
- if (setjmp(oflo_buf) == 0) {
- switch(fcn) {
- case '-': iarg = -iarg;
- case '+':
- if (iarg < 0) {
- nval = ival + iarg;
- if (nval >= ival)
- handle_oflo(sig_arg);
- else ival = nval;
- } else {
- nval = ival + iarg;
- if (nval < ival)
- handle_oflo(sig_arg);
- else ival = nval;
- }
- break;
- case '/':
- if (iarg == 0)
- err_logo(BAD_DATA_UNREC,arg);
- else
- if (ival % iarg != 0) {
- imode = FALSE;
- fval = (FLONUM)ival;
- farg = (FLONUM)iarg;
- }
- else ival /= iarg;
- break;
- case '%':
- ival %= iarg;
- break;
- case 'm':
- ival %= iarg;
- if ((ival < 0) != (iarg < 0))
- ival += iarg;
- break;
- case '&': ival &= iarg; break;
- case '|': ival |= iarg; break;
- case '^': ival ^= iarg; break;
- case 'a':
- case 'l':
- if (iarg < 0) {
- if (fcn == 'a')
- ival >>= -iarg;
- else
- ival = (unsigned)ival
- >> -iarg;
- } else
- ival <<= iarg;
- break;
- case '*':
- if (ival < SAFEINT && ival > -SAFEINT &&
- iarg < SAFEINT && iarg > -SAFEINT) {
- ival *= iarg;
- break;
- }
- wantint++;
- default: /* math library */
- imode = FALSE;
- fval = (FLONUM)ival;
- farg = (FLONUM)iarg;
- }
- } else { /* integer overflow detected */
- imode = FALSE;
- fval = (FLONUM)oval;
- farg = (FLONUM)iarg;
- }
- handling_oflo = FALSE;
- }
- if (imode == FALSE) {
- handling_oflo = TRUE;
- if (setjmp(oflo_buf) == 0) {
- switch(fcn) {
- case '+': fval += farg; break;
- case '-': fval -= farg; break;
- case '*':
- fval *= farg;
- if (wantint) {
- wantint = 0;
- if (fval <= MAXLOGOINT && fval >= -MAXLOGOINT) {
- imode = TRUE;
- ival = fval;
- }
- }
- break;
- case '/': if (farg == 0.0)
- err_logo(BAD_DATA_UNREC,arg);
- else
- fval /= farg;
- break;
- case 't':
- errchk(fval = atan2(farg,fval)/degrad);
- break;
- case 'T':
- errchk(fval = atan2(farg,fval));
- break;
- case 'p':
- errchk(fval = pow(fval,farg));
- break;
- default: /* logical op */
- if (nodetype(arg) == INT)
- err_logo(BAD_DATA_UNREC, make_floatnode(fval));
- else
- err_logo(BAD_DATA_UNREC,arg);
- }
- } else { /* floating overflow detected */
- err_logo(BAD_DATA_UNREC,arg);
- }
- handling_oflo = FALSE;
- } /* end floating point */
- } /* end dyadic */
- if (NOT_THROWING) {
- if (imode) {
- val = newnode(INT);
- setint(val, ival);
- } else {
- val = newnode(FLOATT);
- setfloat(val, fval);
- }
- return(val);
- }
- return(UNBOUND);
- }
-
- NODE *ladd(NODE *args) {
- if (args == NIL) return make_intnode(0L);
- return(binary(args, '+'));
- }
-
- NODE *lsub(NODE *args) {
- return(binary(args, '-'));
- }
-
- NODE *lmul(NODE *args) {
- if (args == NIL) return make_intnode(1L);
- return(binary(args, '*'));
- }
-
- NODE *ldivide(NODE *args) {
- return(binary(args, '/'));
- }
-
- NODE *lremainder(NODE *args) {
- return(binary(args, '%'));
- }
-
- NODE *lmodulo(NODE *args) {
- return(binary(args, 'm'));
- }
-
- NODE *lbitand(NODE *args) {
- if (args == NIL) return make_intnode(-1);
- return(binary(args, '&'));
- }
-
- NODE *lbitor(NODE *args) {
- if (args == NIL) return make_intnode(0);
- return(binary(args, '|'));
- }
-
- NODE *lbitxor(NODE *args) {
- if (args == NIL) return make_intnode(0);
- return(binary(args, '^'));
- }
-
- NODE *lashift(NODE *args) {
- return(binary(args, 'a'));
- }
-
- NODE *llshift(NODE *args) {
- return(binary(args, 'l'));
- }
-
- NODE *lbitnot(NODE *args) {
- return(binary(args, '~'));
- }
-
- NODE *lsin(NODE *args) {
- return(binary(args, 's'));
- }
-
- NODE *lcos(NODE *args) {
- return(binary(args, 'c'));
- }
-
- NODE *latan(NODE *args) {
- return(binary(args, 't'));
- }
-
- NODE *lradsin(NODE *args) {
- return(binary(args, 'S'));
- }
-
- NODE *lradcos(NODE *args) {
- return(binary(args, 'C'));
- }
-
- NODE *lradatan(NODE *args) {
- return(binary(args, 'T'));
- }
-
- NODE *lsqrt(NODE *args) {
- return(binary(args, 'q'));
- }
-
- NODE *linteg(NODE *args) {
- return(binary(args, 'i'));
- }
-
- NODE *lround(NODE *args) {
- return(binary(args, 'r'));
- }
-
- NODE *lexp(NODE *args) {
- return(binary(args, 'e'));
- }
-
- NODE *llog10(NODE *args) {
- return(binary(args, 'g'));
- }
-
- NODE *lln(NODE *args) {
- return(binary(args, 'n'));
- }
-
- NODE *lpower(NODE *args) {
- return(binary(args, 'p'));
- }
-
- int compare_numnodes(NODE *n1, NODE *n2) {
- FLONUM f;
- FIXNUM i;
-
- if (nodetype(n1) == INT) {
- if (nodetype(n2) == INT) {
- i = getint(n1) - getint(n2);
- return (i == 0L ? 0 : (i > 0L ? 1 : -1));
- } else {
- f = (FLONUM)getint(n1) - getfloat(n2);
- return(f == 0.0 ? 0 : (f > 0.0 ? 1 : -1));
- }
- }
- else {
- if (nodetype(n2) == INT) {
- f = getfloat(n1) - (FLONUM)getint(n2);
- return(f == 0.0 ? 0 : (f > 0.0 ? 1 : -1));
- }
- else {
- f = getfloat(n1) - getfloat(n2);
- return(f == 0.0 ? 0 : (f > 0.0 ? 1 : -1));
- }
- }
- }
-
- NODE *torf(BOOLEAN tf) {
- return (tf ? True : False);
- }
-
- NODE *llessp(NODE *args) {
- NODE *n1, *n2;
-
- n1 = numeric_arg(args);
- n2 = numeric_arg(cdr(args));
-
- if (NOT_THROWING) {
- return torf(compare_numnodes(n1, n2) < 0);
- }
- return(UNBOUND);
- }
-
- NODE *lgreaterp(NODE *args) {
- NODE *n1, *n2;
-
- n1 = numeric_arg(args);
- n2 = numeric_arg(cdr(args));
-
- if (NOT_THROWING) {
- return torf(compare_numnodes(n1, n2) > 0);
- }
- return(UNBOUND);
- }
-
- int compare_node(NODE *n1, NODE *n2, BOOLEAN ignorecase) {
- NODE *a1 = NIL, *a2 = NIL, *nn1 = NIL, *nn2 = NIL;
- int icmp = 0, cmp_len;
- NODETYPES nt1, nt2;
-
- if (n1 == n2) return 0;
-
- nt1 = nodetype(n1);
- nt2 = nodetype(n2);
-
- if (!(nt1 & NT_WORD) || !(nt2 & NT_WORD)) return -9999;
-
- if (nt1 == CASEOBJ && nt2 == CASEOBJ && ignorecase &&
- (object__caseobj(n1) == object__caseobj(n2))) return 0;
-
- if ((nt1 & NT_NUMBER) && (nt2 & NT_NUMBER))
- return compare_numnodes(n1, n2);
-
- if (nt1 & NT_NUMBER) {
- nn2 = cnv_node_to_numnode(n2);
- if (nn2 != UNBOUND) {
- icmp = compare_numnodes(n1, nn2);
- return icmp;
- }
- }
-
- if (nt2 & NT_NUMBER) {
- nn1 = cnv_node_to_numnode(n1);
- if (nn1 != UNBOUND) {
- icmp = compare_numnodes(nn1, n2);
- return icmp;
- }
- }
-
- a1 = cnv_node_to_strnode(n1);
- a2 = cnv_node_to_strnode(n2);
- nt1 = nodetype(a1);
- nt2 = nodetype(a2);
- if (nt1 == STRING && nt2 == STRING) {
- if ((getstrlen(a1) == getstrlen(a2)) &&
- (getstrptr(a1) == getstrptr(a2)))
- icmp = 0;
- else {
- cmp_len = (getstrlen(a1) > getstrlen(a2)) ?
- getstrlen(a2) : getstrlen(a1);
-
- if (ignorecase)
- icmp = low_strncmp(getstrptr(a1), getstrptr(a2), cmp_len);
- else
- icmp = strncmp(getstrptr(a1), getstrptr(a2), cmp_len);
- if ((getstrlen(a1) != getstrlen(a2)) && icmp == 0)
- icmp = getstrlen(a1) - getstrlen(a2);
- }
- }
- else if (nt1 & NT_BACKSL || nt2 & NT_BACKSL) {
- if ((getstrlen(a1) == getstrlen(a2)) &&
- (getstrptr(a1) == getstrptr(a2)))
- icmp = 0;
- else {
- cmp_len = (getstrlen(a1) > getstrlen(a2)) ?
- getstrlen(a2) : getstrlen(a1);
-
- if (ignorecase)
- icmp = noparitylow_strncmp(getstrptr(a1), getstrptr(a2), cmp_len);
- else
- icmp = noparity_strncmp(getstrptr(a1), getstrptr(a2), cmp_len);
- if ((getstrlen(a1) != getstrlen(a2)) && icmp == 0)
- icmp = getstrlen(a1) - getstrlen(a2);
- }
- }
- else err_logo(FATAL, NIL);
-
- return(icmp);
- }
-
- BOOLEAN equalp_help(NODE *arg1, NODE *arg2, BOOLEAN ignc) {
- if (is_list(arg1)) {
- if (!is_list(arg2)) return FALSE;
- while (arg1 != NIL && arg2 != NIL) {
- if (!equalp_help(car(arg1), car(arg2), ignc))
- return FALSE;
- arg1 = cdr(arg1);
- arg2 = cdr(arg2);
- if (check_throwing) break;
- }
- return (arg1 == NIL && arg2 == NIL);
- } else if (is_list(arg2))
- return FALSE;
- else if (nodetype(arg1) == ARRAY) {
- if (nodetype(arg2) != ARRAY) return FALSE;
- return (arg1 == arg2);
- } else if (nodetype(arg2) == ARRAY)
- return FALSE;
- else return (!compare_node(arg1, arg2, ignc));
- }
-
- NODE *lequalp(NODE *args) {
- NODE *arg1, *arg2;
- BOOLEAN val;
-
- arg1 = car(args);
- arg2 = cadr(args);
-
- if (compare_node(valnode__caseobj(Caseignoredp), True, TRUE) == 0)
- val = equalp_help(arg1, arg2, TRUE);
- else
- val = equalp_help(arg1, arg2, FALSE);
-
- return(torf(val));
- }
-
- NODE *l_eq(NODE *args) {
- return torf(car(args) == cadr(args));
- }
-
- NODE *lbeforep(NODE *args) {
- NODE *arg1, *arg2;
- int val;
-
- arg1 = string_arg(args);
- arg2 = string_arg(cdr(args));
-
- if (compare_node(valnode__caseobj(Caseignoredp), True, TRUE) == 0)
- val = compare_node(arg1, arg2, TRUE);
- else
- val = compare_node(arg1, arg2, FALSE);
-
- return (val < 0 ? True : False);
- }
-