/* "scl.c" non-IEEE utility functions and non-integer arithmetic.
* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1997, 2005, 2006 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see
* .
*/
/* Authors: Jerry D. Hedden and Aubrey Jaffer */
#include "scm.h"
#ifdef FLOATS
# ifndef PLAN9
# include
# endif
static double big2scaldbl P((SCM b, int expt));
static SCM bigdblop P((int op, SCM b, double re, double im));
static SCM inex_divbigbig P((SCM a, SCM b));
static int apx_log10 P((double x));
static double lpow10 P((double x, int n));
static sizet idbl2str P((double f, char *a));
static sizet iflo2str P((SCM flt, char *str));
static void safe_add_1 P((double f, double *fsum));
static long scm_twos_power P((SCM n));
static char s_makrect[] = "make-rectangular", s_makpolar[] = "make-polar",
s_magnitude[] = "magnitude", s_angle[] = "angle",
s_real_part[] = "real-part", s_imag_part[] = "imag-part",
s_in2ex[] = "inexact->exact",s_ex2in[] = "exact->inexact";
static char s_expt[] = "real-expt", s_atan2[] = "$atan2";
#endif
static char s_memv[] = "memv", s_assv[] = "assv";
SCM sys_protects[NUM_PROTECTS];
sizet num_protects = NUM_PROTECTS;
char s_inexactp[] = "inexact?";
static char s_zerop[] = "zero?", s_abs[] = "abs",
s_positivep[] = "positive?", s_negativep[] = "negative?";
static char s_lessp[] = "<", s_grp[] = ">";
static char s_leqp[] = "<=", s_greqp[] = ">=";
#define s_eqp (&s_leqp[1])
static char s_max[] = "max", s_min[] = "min";
char s_sum[] = "+", s_difference[] = "-", s_product[] = "*",
s_divide[] = "/";
static char s_number2string[] = "number->string",
s_str2number[] = "string->number";
static char s_list_tail[] = "list-tail";
static char s_str2list[] = "string->list";
static char s_st_copy[] = "string-copy", s_st_fill[] = "string-fill!";
static char s_vect2list[] = "vector->list", s_ve_fill[] = "vector-fill!";
static char s_intexpt[] = "integer-expt";
static char str_inf0[] = "inf.0";
/*** NUMBERS -> STRINGS ***/
#ifdef FLOATS
static int dbl_mant_dig = 0;
static double max_dbl_int; /* Integers less than or equal to max_dbl_int
are representable exactly as doubles. */
static double dbl_eps;
double dbl_prec(x)
double x;
{
int expt;
double frac = frexp(x, &expt);
# ifdef DBL_MIN_EXP
if (0.0==x || expt < DBL_MIN_EXP) /* gradual underflow */
return ldexp(1.0, - dbl_mant_dig) * ldexp(1.0, DBL_MIN_EXP);
# endif
if (1.0==frac) return ldexp(1.0, expt - dbl_mant_dig + 1);
return ldexp(1.0, expt - dbl_mant_dig);
}
static double llog2 = 0.3010299956639812; /* log10(2) */
static int apx_log10(x)
double x;
{
int expt;
frexp(x, &expt);
expt -= 1;
if (expt >= 0)
return (int)(expt * llog2);
return -((int)(-expt * llog2));
}
static double p10[] = {1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7};
static double lpow10(x, n)
double x;
int n;
{
if (n >= 0) {
while (n > 7) {
x *= 1e8;
n -= 8;
}
return x*p10[n];
}
while (n < -7) {
x /= 1e8;
n += 8;
}
return x/p10[-n];
}
int inf2str(f, a)
double f;
char *a;
{
sizet ch = 0;
if (f < 0.0) a[ch++] = '-';
else if (f > 0.0) a[ch++] = '+';
else {
a[ch++] = '0'; a[ch++] = '/'; a[ch++] = '0';
return ch;
}
while (str_inf0[ch - 1]) {
a[ch] = str_inf0[ch - 1];
ch++;
}
/* # ifdef COMPACT_INFINITY_NOTATION */
/* else a[ch++] = '0'; */
/* # else */
/* a[ch++] = (f != f) ? '0' : '1'; */
/* # endif */
/* a[ch++] = '/'; a[ch++] = '0'; */
return ch;
}
/* DBL2STR_FUZZ is a somewhat arbitrary guard against
round off error in scaling f and fprec. */
# define DBL2STR_FUZZ 0.9
int dblprec;
static sizet idbl2str(f, a)
double f;
char *a;
{
double fprec = dbl_prec(f);
int efmt, dpt, d, i, exp;
sizet ch = 0;
if (f==0.0) {exp = 0; goto zero;} /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;}*/
if (f==2*f) return inf2str(f, a);
if (f < 0.0) {f = -f;a[ch++]='-';}
else if (f > 0.0) ;
else return inf2str(f, a);
exp = apx_log10(f);
f = lpow10(f, -exp);
fprec = lpow10(fprec, -exp);
# ifdef DBL_MIN_10_EXP /* Prevent random unnormalized values, as from
make-uniform-vector, from causing infinite loops,
but try to print gradually underflowing numbers. */
while (f < 1.0) {
f *= 10.0;
fprec *= 10.0;
if (exp-- < DBL_MIN_10_EXP - DBL_DIG - 1) return inf2str(f, a);
}
while (f > 10.0) {
f /= 10.0;
fprec /= 10.0;
if (exp++ > DBL_MAX_10_EXP) return inf2str(f, a);
}
# else
while (f < 1.0) {f *= 10.0; fprec *= 10.0; exp--;}
while (f > 10.0) {f /= 10.0; fprec /= 10.0; exp++;}
# endif
fprec *= 0.5;
if (f+fprec >= 10.0) {f = 1.0; exp++;}
zero:
# ifdef ENGNOT
dpt = (exp+9999)%3;
exp -= dpt++;
efmt = 1;
# else
efmt = (exp < -3) || (exp > dblprec+2);
if (!efmt)
if (exp < 0) {
a[ch++] = '0';
a[ch++] = '.';
dpt = exp;
while (++dpt) a[ch++] = '0';
} else
dpt = exp+1;
else
dpt = 1;
# endif
for (i = 30; i--;) {
/* printf(" f = %.20g, fprec = %.20g, i = %d\n", f, fprec, i); */
d = f;
f -= d;
a[ch++] = d+'0';
if (f < fprec && f < DBL2STR_FUZZ*fprec) break;
if ((f + fprec) >= 1.0 && (f + DBL2STR_FUZZ*fprec) >= 1.0) {
a[ch-1]++;
break;
}
f *= 10.0;
fprec *= 10.0;
if (!(--dpt)) a[ch++] = '.';
}
if (dpt > 0)
# ifndef ENGNOT
if ((dpt > 4) && (exp > 6)) {
d = (a[0]=='-'?2:1);
for (i = ch++; i > d; i--)
a[i] = a[i-1];
a[d] = '.';
efmt = 1;
} else
# endif
{
while (--dpt) a[ch++] = '0';
a[ch++] = '.';
}
if (a[ch-1]=='.') a[ch++]='0'; /* trailing zero */
if (efmt && exp) {
a[ch++] = 'e';
if (exp < 0) {
exp = -exp;
a[ch++] = '-';
}
for (i = 10; i <= exp; i *= 10);
for (i /= 10; i; i /= 10) {
a[ch++] = exp/i + '0';
exp %= i;
}
}
return ch;
}
static sizet iflo2str(flt, str)
SCM flt;
char *str;
{
sizet i;
# ifdef SINGLES
if (SINGP(flt)) i = idbl2str(FLO(flt), str);
else
# endif
i = idbl2str(REAL(flt), str);
if (scm_narn==flt) return i;
if (CPLXP(flt)) {
if (!(0 > IMAG(flt))) str[i++] = '+';
i += idbl2str(IMAG(flt), &str[i]);
str[i++] = 'i';
}
return i;
}
#endif /* FLOATS */
sizet iuint2str(num, rad, p)
unsigned long num;
int rad;
char *p;
{
sizet j;
register int i = 1, d;
register unsigned long n = num;
for (n /= rad;n > 0;n /= rad) i++;
j = i;
n = num;
while (i--) {
d = n % rad;
n /= rad;
p[i] = d + ((d < 10) ? '0' : 'a' - 10);
}
return j;
}
sizet iint2str(num, rad, p)
long num;
int rad;
char *p;
{
if ((num < 0) && !(rad < 0)) {
*p++ = '-';
return 1 + iuint2str((unsigned long) -num, rad, p);
}
return iuint2str((unsigned long) num, rad < 0 ? -rad : rad, p);
}
#ifdef BIGDIG
static SCM big2str(b, radix)
SCM b;
register unsigned int radix;
{
SCM t = copybig(b, 0); /* sign of temp doesn't matter */
register BIGDIG *ds = BDIGITS(t);
sizet i = NUMDIGS(t);
sizet j = radix==16 ? (BITSPERDIG*i)/4+2
: radix >= 10 ? (BITSPERDIG*i*241L)/800+2
: (BITSPERDIG*i)+2;
sizet k = 0;
sizet radct = 0;
sizet ch; /* jeh */
BIGDIG radpow = 1, radmod = 0;
SCM ss = makstr((long)j);
char *s = CHARS(ss), c;
scm_protect_temp(&t);
while ((long) radpow * radix < BIGRAD) {
radpow *= radix;
radct++;
}
s[0] = tc16_bigneg==TYP16(b) ? '-' : '+';
while ((i || radmod) && j) {
if (k==0) {
radmod = (BIGDIG)divbigdig(ds, i, radpow);
k = radct;
if (!ds[i-1]) i--;
}
c = radmod % radix; radmod /= radix; k--;
s[--j] = c < 10 ? c + '0' : c + 'a' - 10;
}
ch = s[0]=='-' ? 1 : 0; /* jeh */
if (ch < j) { /* jeh */
for (i = j;j < LENGTH(ss);j++) s[ch+j-i] = s[j]; /* jeh */
resizuve(ss, (SCM)MAKINUM(ch+LENGTH(ss)-i)); /* jeh */
}
return ss;
}
#endif
SCM number2string(x, radix)
SCM x, radix;
{
if (UNBNDP(radix)) radix=MAKINUM(10L);
else ASRTER(INUMP(radix), radix, ARG2, s_number2string);
#ifdef FLOATS
if (NINUMP(x)) {
char num_buf[FLOBUFLEN];
# ifdef BIGDIG
ASRTGO(NIMP(x), badx);
if (BIGP(x)) return big2str(x, (unsigned int)INUM(radix));
# ifndef RECKLESS
if (!(INEXP(x)))
badx: wta(x, (char *)ARG1, s_number2string);
# endif
# else
ASRTER(NIMP(x) && INEXP(x), x, ARG1, s_number2string);
# endif
return makfromstr(num_buf, iflo2str(x, num_buf));
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_number2string);
return big2str(x, (unsigned int)INUM(radix));
}
# else
ASRTER(INUMP(x), x, ARG1, s_number2string);
# endif
#endif
{
char num_buf[INTBUFLEN];
return makfromstr(num_buf, iint2str(INUM(x), (int)INUM(radix), num_buf));
}
}
/* These print routines are stubbed here so that repl.c doesn't need
FLOATS or BIGDIGs conditionals */
int floprint(sexp, port, writing)
SCM sexp;
SCM port;
int writing;
{
#ifdef FLOATS
if (!errjmp_bad) {
char num_buf[FLOBUFLEN];
lfwrite(num_buf, (sizet)sizeof(char), iflo2str(sexp, num_buf), port);
return !0;
} else
#endif
scm_ipruk("float", sexp, port);
return !0;
}
int bigprint(exp, port, writing)
SCM exp;
SCM port;
int writing;
{
#ifdef BIGDIG
if (!errjmp_bad) {
exp = big2str(exp, (unsigned int)10);
lfwrite(CHARS(exp), (sizet)sizeof(char), (sizet)LENGTH(exp), port);
return !0;
} else
#endif
scm_ipruk("bignum", exp, port);
return !0;
}
/*** END nums->strs ***/
/*** STRINGS -> NUMBERS ***/
#ifdef BIGDIG
SCM istr2int(str, len, radix)
char *str;
long len;
register long radix;
{
sizet j;
register sizet k, blen = 1;
sizet i = 0;
int c;
SCM res;
register BIGDIG *ds;
register unsigned long t2;
if (0 >= len) return BOOL_F; /* zero length */
if (10==radix) j = 1+(84*len)/(BITSPERDIG*25);
else j = (8 < radix) ? 1+(4*len)/BITSPERDIG : 1+(3*len)/BITSPERDIG;
switch (str[0]) { /* leading sign */
case '-':
case '+': if (++i==len) return BOOL_F; /* bad if lone `+' or `-' */
}
res = mkbig(j, '-'==str[0]);
ds = BDIGITS(res);
for (k = j;k--;) ds[k] = 0;
do {
switch (c = str[i++]) {
case DIGITS:
c = c - '0';
goto accumulate;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
c = c-'A'+10;
goto accumulate;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
c = c-'a'+10;
accumulate:
if (c >= radix) return BOOL_F; /* bad digit for radix */
k = 0;
t2 = c;
moretodo:
while(k < blen) {
/* printf("k = %d, blen = %d, t2 = %ld, ds[k] = %d\n", k, blen, t2, ds[k]);*/
t2 += ds[k]*radix;
ds[k++] = BIGLO(t2);
t2 = BIGDN(t2);
}
ASRTER(blen <= j, (SCM)MAKINUM(blen), OVFLOW, "bignum");
if (t2) {blen++; goto moretodo;}
break;
default:
return BOOL_F; /* not a digit */
}
} while (i < len);
if (blen * BITSPERDIG/CHAR_BIT <= sizeof(SCM))
if (INUMP(res = big2inum(res, blen))) return res;
if (j==blen) return res;
return adjbig(res, blen);
}
#else
SCM istr2int(str, len, radix)
register char *str;
long len;
register long radix;
{
register long n = 0, ln;
register int c;
register int i = 0;
int lead_neg = 0;
if (0 >= len) return BOOL_F; /* zero length */
switch (*str) { /* leading sign */
case '-': lead_neg = 1;
case '+': if (++i==len) return BOOL_F; /* bad if lone `+' or `-' */
}
do {
switch (c = str[i++]) {
case DIGITS:
c = c - '0';
goto accumulate;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
c = c-'A'+10;
goto accumulate;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
c = c-'a'+10;
accumulate:
if (c >= radix) return BOOL_F; /* bad digit for radix */
ln = n;
n = n * radix - c;
if (n > ln
# ifdef hpux
|| (-n > -MOST_NEGATIVE_FIXNUM) /* workaround for HP700 cc bug */
# endif
) goto ovfl;
break;
default:
return BOOL_F; /* not a digit */
}
} while (i < len);
if (lead_neg) {
if (n < MOST_NEGATIVE_FIXNUM) goto ovfl;
}
else {
if (n < -MOST_POSITIVE_FIXNUM) goto ovfl;
n = -n;
}
return MAKINUM(n);
ovfl: /* overflow scheme integer */
return BOOL_F;
}
#endif
#ifdef FLOATS
# ifdef BIGDIG
static char twostab[] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
static long scm_twos_power(n)
SCM n;
{
long d, c = 0;
int d4;
# ifdef BIGDIG
if (NINUMP(n)) {
BIGDIG *ds;
int i = 0;
ds = BDIGITS(n);
while (0==(d = ds[i++])) c += BITSPERDIG;
goto out;
}
# endif
d = INUM(n);
if (0==d) return 0;
out:
do {
d4 = 15 & d;
c += twostab[d4];
d >>= 4;
} while (0==d4);
return c;
}
# endif /* def BIGDIG */
SCM istr2flo(str, len, radix)
register char *str;
register long len;
register long radix;
{
register int c, i = 0;
double lead_sgn = 0.0;
double res = 0.0, tmp = 0.0;
int flg = 0;
int point = 0;
SCM second;
if (i >= len) return BOOL_F; /* zero length */
switch (*str) { /* leading sign */
case '-': lead_sgn = -1.0; i++; break;
case '+': lead_sgn = 1.0; i++; break;
}
if (i==len) return BOOL_F; /* bad if lone `+' or `-' */
if (6==len && ('+'==str[0] || '-'==str[0]))
if (0==strcmp(str_inf0, &str[1]))
return makdbl(1./0. * ('+'==str[0] ? 1 : -1), 0.0);
if (str[i]=='i' || str[i]=='I') { /* handle `+i' and `-i' */
if (lead_sgn==0.0) return BOOL_F; /* must have leading sign */
if (++i < len) return BOOL_F; /* `i' not last character */
return makdbl(0.0, lead_sgn);
}
/* # ifdef COMPACT_INFINITY_NOTATION */
if (0.0 != lead_sgn && str[i]=='/') {
res = 1;
flg = 1;
goto out1;
}
/* # endif */
do { /* check initial digits */
switch (c = str[i]) {
case DIGITS:
c = c - '0';
goto accum1;
case 'D': case 'E': case 'F':
if (radix==10) goto out1; /* must be exponent */
case 'A': case 'B': case 'C':
c = c-'A'+10;
goto accum1;
case 'd': case 'e': case 'f':
if (radix==10) goto out1;
case 'a': case 'b': case 'c':
c = c-'a'+10;
accum1:
if (c >= radix) return BOOL_F; /* bad digit for radix */
res = res * radix + c;
flg = 1; /* res is valid */
break;
default:
goto out1;
}
} while (++i < len);
out1:
/* if true, then we did see a digit above, and res is valid */
if (i==len) goto done;
/* By here, must have seen a digit,
or must have next char be a `.' with radix==10 */
if (!flg)
if (!(str[i]=='.' && radix==10))
return BOOL_F;
while (str[i]=='#') { /* optional sharps */
res *= radix;
if (++i==len) goto done;
}
if (str[i]=='/') {
while (++i < len) {
switch (c = str[i]) {
case DIGITS:
c = c - '0';
goto accum2;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
c = c-'A'+10;
goto accum2;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
c = c-'a'+10;
accum2:
if (c >= radix) return BOOL_F;
tmp = tmp * radix + c;
break;
default:
goto out2;
}
}
out2:
/* if (tmp==0.0) return BOOL_F; /\* `slash zero' not allowed *\/ */
if (i < len)
while (str[i]=='#') { /* optional sharps */
tmp *= radix;
if (++i==len) break;
}
res /= tmp;
goto done;
}
if (str[i]=='.') { /* decimal point notation */
if (radix != 10) return BOOL_F; /* must be radix 10 */
while (++i < len) {
switch (c = str[i]) {
case DIGITS:
point--;
res = res*10.0 + c-'0';
flg = 1;
break;
default:
goto out3;
}
}
out3:
if (!flg) return BOOL_F; /* no digits before or after decimal point */
if (i==len) goto adjust;
while (str[i]=='#') { /* ignore remaining sharps */
if (++i==len) goto adjust;
}
}
switch (str[i]) { /* exponent */
case 'd': case 'D':
case 'e': case 'E':
case 'f': case 'F':
case 'l': case 'L':
case 's': case 'S': {
int expsgn = 1, expon = 0;
if (radix != 10) return BOOL_F; /* only in radix 10 */
if (++i==len) return BOOL_F; /* bad exponent */
switch (str[i]) {
case '-': expsgn=(-1);
case '+': if (++i==len) return BOOL_F; /* bad exponent */
}
if (str[i] < '0' || str[i] > '9') return BOOL_F; /* bad exponent */
do {
switch (c = str[i]) {
case DIGITS:
expon = expon*10 + c-'0';
/* if (expon > MAXEXP) */
/* if (1==expsgn || expon > (MAXEXP + dblprec + 1)) */
/* return BOOL_F; /\* exponent too large *\/ */
break;
default:
goto out4;
}
} while (++i < len);
out4:
point += expsgn*expon;
}
}
adjust:
if (point >= 0)
while (point--) res *= 10.0;
else
# ifdef _UNICOS
while (point++) res *= 0.1;
# else
while (point++) res /= 10.0;
# endif
done:
/* at this point, we have a legitimate floating point result */
if (lead_sgn==-1.0) res = -res;
if (i==len) return makdbl(res, 0.0);
if (str[i]=='i' || str[i]=='I') { /* pure imaginary number */
if (lead_sgn==0.0) return BOOL_F; /* must have leading sign */
if (++i < len) return BOOL_F; /* `i' not last character */
return makdbl(0.0, res);
}
switch (str[i++]) {
case '-': lead_sgn = -1.0; break;
case '+': lead_sgn = 1.0; break;
case '@': { /* polar input for complex number */
/* get a `real' for angle */
second = istr2flo(&str[i], (long)(len-i), radix);
if (IMP(second)) return BOOL_F;
if (!(INEXP(second))) return BOOL_F; /* not `real' */
if (CPLXP(second)) return BOOL_F; /* not `real' */
tmp = REALPART(second);
return makdbl(res*cos(tmp), res*sin(tmp));
}
default: return BOOL_F;
}
/* at this point, last char must be `i' */
if (str[len-1] != 'i' && str[len-1] != 'I') return BOOL_F;
/* handles `x+i' and `x-i' */
if (i==(len-1)) return makdbl(res, lead_sgn);
/* get a `ureal' for complex part */
second = istr2flo(&str[i], (long)((len-i)-1), radix);
if (IMP(second)) return BOOL_F;
if (!(INEXP(second))) return BOOL_F; /* not `ureal' */
if (CPLXP(second)) return BOOL_F; /* not `ureal' */
tmp = REALPART(second);
if (tmp < 0.0) return BOOL_F; /* not `ureal' */
return makdbl(res, (lead_sgn*tmp));
}
#endif /* FLOATS */
SCM istring2number(str, len, radix)
char *str;
long len;
long radix;
{
int i = 0;
char ex = 0;
char ex_p = 0, rx_p = 0; /* Only allow 1 exactness and 1 radix prefix */
SCM res;
if (len==1)
if (*str=='+' || *str=='-') /* Catches lone `+' and `-' for speed */
return BOOL_F;
while ((len-i) >= 2 && str[i]=='#' && ++i)
switch (str[i++]) {
case 'b': case 'B': if (rx_p++) return BOOL_F; radix = 2; break;
case 'o': case 'O': if (rx_p++) return BOOL_F; radix = 8; break;
case 'd': case 'D': if (rx_p++) return BOOL_F; radix = 10; break;
case 'x': case 'X': if (rx_p++) return BOOL_F; radix = 16; break;
case 'i': case 'I': if (ex_p++) return BOOL_F; ex = 2; break;
case 'e': case 'E': if (ex_p++) return BOOL_F; ex = 1; break;
default: return BOOL_F;
}
switch (ex) {
case 1:
return istr2int(&str[i], len-i, radix);
case 0:
res = istr2int(&str[i], len-i, radix);
if (NFALSEP(res)) return res;
#ifdef FLOATS
case 2: return istr2flo(&str[i], len-i, radix);
#endif
}
return BOOL_F;
}
SCM string2number(str, radix)
SCM str, radix;
{
if (UNBNDP(radix)) radix=MAKINUM(10L);
else ASRTER(INUMP(radix), radix, ARG2, s_str2number);
ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_str2number);
return istring2number(CHARS(str), LENGTH(str), INUM(radix));
}
/*** END strs->nums ***/
#ifdef FLOATS
SCM makdbl (x, y)
double x, y;
{
SCM z;
if ((y==0.0) && (x==0.0)) return flo0;
# ifndef _MSC_VER
# ifndef SINGLESONLY
if ((y != y) || (x != x) || (y==(2 * y) && (y != 0.0))) return scm_narn;
if ((x==(2 * x)) && (x != 0.0)) y = 0.0;
# endif
# endif
DEFER_INTS;
if (y==0.0) {
# ifdef SINGLES
float fx = x; /* David Yeh
changed this so that MSVC works */
# ifndef SINGLESONLY
if ((-FLTMAX < x) && (x < FLTMAX) && ( (double)fx == x) )
# endif
{
NEWCELL(z);
CAR(z) = tc_flo;
FLO(z) = x;
ALLOW_INTS;
return z;
}
# endif /* def SINGLES */
z = must_malloc_cell(1L*sizeof(double), (SCM)tc_dblr, "real");
}
else {
z = must_malloc_cell(2L*sizeof(double), (SCM)tc_dblc, "complex");
IMAG(z) = y;
}
REAL(z) = x;
ALLOW_INTS;
return z;
}
#endif /* FLOATS */
#ifndef INUMS_ONLY
SCM eqv(x, y)
SCM x, y;
{
if (x==y) return BOOL_T;
if (IMP(x)) return BOOL_F;
if (IMP(y)) return BOOL_F;
/* this ensures that types and length are the same. */
if (CAR(x) != CAR(y)) return BOOL_F;
if (NUMP(x)) {
# ifdef BIGDIG
if (BIGP(x)) return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F;
# endif
# ifdef FLOATS
return floequal(x, y);
# endif
}
return BOOL_F;
}
SCM memv(x, lst) /* m.borza 12.2.91 */
SCM x, lst;
{
for (;NIMP(lst);lst = CDR(lst)) {
ASRTGO(CONSP(lst), badlst);
if (NFALSEP(eqv(CAR(lst), x))) return lst;
}
# ifndef RECKLESS
if (!(NULLP(lst)))
badlst: wta(lst, (char *)ARG2, s_memv);
# endif
return BOOL_F;
}
SCM assv(x, alist) /* m.borza 12.2.91 */
SCM x, alist;
{
SCM tmp;
for (;NIMP(alist);alist = CDR(alist)) {
ASRTGO(CONSP(alist), badlst);
tmp = CAR(alist);
ASRTGO(NIMP(tmp) && CONSP(tmp), badlst);
if (NFALSEP(eqv(CAR(tmp), x))) return tmp;
}
# ifndef RECKLESS
if (!(NULLP(alist)))
badlst: wta(alist, (char *)ARG2, s_assv);
# endif
return BOOL_F;
}
#endif
SCM list_tail(lst, k)
SCM lst, k;
{
register long i;
ASRTER(INUMP(k), k, ARG2, s_list_tail);
i = INUM(k);
while (i-- > 0) {
ASRTER(NIMP(lst) && CONSP(lst), lst, ARG1, s_list_tail);
lst = CDR(lst);
}
return lst;
}
SCM string2list(str)
SCM str;
{
long i;
SCM res = EOL;
unsigned char *src;
ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_str2list);
src = UCHARS(str);
for (i = LENGTH(str)-1;i >= 0;i--) res = cons((SCM)MAKICHR(src[i]), res);
return res;
}
SCM string_copy(str)
SCM str;
{
ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_st_copy);
return makfromstr(CHARS(str), (sizet)LENGTH(str));
}
SCM string_fill(str, chr)
SCM str, chr;
{
register char *dst, c;
register long k;
ASRTER(NIMP(str) && STRINGP(str), str, ARG1, s_st_fill);
ASRTER(ICHRP(chr), chr, ARG2, s_st_fill);
c = ICHR(chr);
dst = CHARS(str);
for (k = LENGTH(str)-1;k >= 0;k--) dst[k] = c;
return UNSPECIFIED;
}
SCM vector2list(v)
SCM v;
{
SCM res = EOL;
long i;
SCM *data;
ASRTER(NIMP(v) && VECTORP(v), v, ARG1, s_vect2list);
data = VELTS(v);
for (i = LENGTH(v)-1;i >= 0;i--) res = cons(data[i], res);
return res;
}
SCM vector_fill(v, fill)
SCM v, fill;
{
register long i;
register SCM *data;
ASRTER(NIMP(v) && VECTORP(v), v, ARG1, s_ve_fill);
data = VELTS(v);
for (i = LENGTH(v)-1;i >= 0;i--) data[i] = fill;
return UNSPECIFIED;
}
static SCM vector_equal(x, y)
SCM x, y;
{
long i;
for (i = LENGTH(x)-1;i >= 0;i--)
if (FALSEP(equal(VELTS(x)[i], VELTS(y)[i]))) return BOOL_F;
return BOOL_T;
}
#ifdef BIGDIG
SCM bigequal(x, y)
SCM x, y;
{
if (0==bigcomp(x, y)) return BOOL_T;
return BOOL_F;
}
#endif
#ifdef FLOATS
SCM floequal(x, y)
SCM x, y;
{
if ((REALPART(x) != REALPART(y))) return BOOL_F;
if (CPLXP(x))
return (CPLXP(y) && (IMAG(x)==IMAG(y))) ? BOOL_T : BOOL_F;
return CPLXP(y) ? BOOL_F : BOOL_T;
}
#endif
SCM equal(x, y)
SCM x, y;
{
CHECK_STACK;
tailrecurse: POLL;
if (x==y) return BOOL_T;
if (IMP(x)) return BOOL_F;
if (IMP(y)) return BOOL_F;
if (CONSP(x) && CONSP(y)) {
if (FALSEP(equal(CAR(x), CAR(y)))) return BOOL_F;
x = CDR(x);
y = CDR(y);
goto tailrecurse;
}
/* this ensures that types and length are the same. */
if (CAR(x) != CAR(y)) return BOOL_F;
switch (TYP7(x)) {
default: return BOOL_F;
case tc7_string: return st_equal(x, y);
case tc7_vector: return vector_equal(x, y);
case tc7_smob: {
int i = SMOBNUM(x);
if (!(i < numsmob)) return BOOL_F;
if (smobs[i].equalp) return (smobs[i].equalp)(x, y);
else return BOOL_F;
}
case tc7_Vbool: case tc7_VfixN8: case tc7_VfixZ8:
case tc7_VfixN16: case tc7_VfixZ16: case tc7_VfixN32: case tc7_VfixZ32:
case tc7_VfloR32: case tc7_VfloC32: case tc7_VfloC64: case tc7_VfloR64: {
SCM (*pred)() = smobs[0x0ff & (tc16_array>>8)].equalp;
if (pred) return (*pred)(x, y);
else return BOOL_F;
}
}
}
SCM numberp(obj)
SCM obj;
{
if (INUMP(obj)) return BOOL_T;
#ifdef FLOATS
if (NIMP(obj) && NUMP(obj)) return BOOL_T;
#else
# ifdef BIGDIG
if (NIMP(obj) && NUMP(obj)) return BOOL_T;
# endif
#endif
return BOOL_F;
}
#ifdef FLOATS
SCM scm_complex_p(obj)
SCM obj;
{
if (obj==scm_narn) return BOOL_F;
return numberp(obj);
}
# ifdef BIGDIG
int scm_bigdblcomp(b, d)
SCM b;
double d;
{
sizet dlen, blen;
int dneg = d < 0 ? 1 : 0;
int bneg = BIGSIGN(b) ? 1 : 0;
if (bneg < dneg) return -1;
if (bneg > dneg) return 1;
frexp(d, &dlen);
blen = INUM(scm_intlength(b));
if (blen > dlen) return dneg ? 1 : -1;
if (blen < dlen) return dneg ? -1 : 1;
if ((blen <= dbl_mant_dig) || (blen - scm_twos_power(b)) <= dbl_mant_dig) {
double bd = big2dbl(b);
if (bd > d) return -1;
if (bd < d) return 1;
return 0;
}
return bigcomp(b, dbl2big(d));
}
# endif
SCM realp(x)
SCM x;
{
if (INUMP(x)) return BOOL_T;
if (IMP(x)) return BOOL_F;
if (REALP(x)) return BOOL_T;
# ifdef BIGDIG
if (BIGP(x)) return BOOL_T;
# endif
return BOOL_F;
}
SCM scm_rationalp(x)
SCM x;
{
if (INUMP(x)) return BOOL_T;
if (IMP(x)) return BOOL_F;
if (REALP(x)) {
float y = REALPART(x);
if (y==2*y && y != 0.0) return BOOL_F;
return BOOL_T;
}
# ifdef BIGDIG
if (BIGP(x)) return BOOL_T;
# endif
return BOOL_F;
}
SCM intp(x)
SCM x;
{
double r;
if (INUMP(x)) return BOOL_T;
if (IMP(x)) return BOOL_F;
# ifdef BIGDIG
if (BIGP(x)) return BOOL_T;
# endif
if (!INEXP(x)) return BOOL_F;
if (CPLXP(x)) return BOOL_F;
r = REALPART(x);
if (r != floor(r)) return BOOL_F;
if (r==2*r && r != 0.0) return BOOL_F;
return BOOL_T;
}
#endif /* FLOATS */
SCM inexactp(x)
SCM x;
{
#ifdef FLOATS
if (NIMP(x) && INEXP(x)) return BOOL_T;
#endif
return BOOL_F;
}
SCM eqp(x, y)
SCM x, y;
{
#ifdef FLOATS
SCM t;
if (NINUMP(x)) {
# ifdef BIGDIG
# ifndef RECKLESS
if (!(NIMP(x)))
badx: wta(x, (char *)ARG1, s_eqp);
# endif
if (BIGP(x)) {
if (INUMP(y)) return BOOL_F;
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F;
ASRTGO(INEXP(y), bady);
bigreal:
return (REALP(y) && (0==scm_bigdblcomp(x, REALPART(y)))) ?
BOOL_T : BOOL_F;
}
ASRTGO(INEXP(x), badx);
# else
ASRTER(NIMP(x) && INEXP(x), x, ARG1, s_eqp);
# endif
if (INUMP(y)) {t = x; x = y; y = t; goto realint;}
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {t = x; x = y; y = t; goto bigreal;}
ASRTGO(INEXP(y), bady);
# else
ASRTGO(NIMP(y) && INEXP(y), bady);
# endif
if (x==y) return BOOL_T;
return floequal(x, y);
}
if (NINUMP(y)) {
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return BOOL_F;
# ifndef RECKLESS
if (!(INEXP(y)))
bady: wta(y, (char *)ARG2, s_eqp);
# endif
# else
# ifndef RECKLESS
if (!(NIMP(y) && INEXP(y)))
bady: wta(y, (char *)ARG2, s_eqp);
# endif
# endif
realint:
return (REALP(y) && (((double)INUM(x))==REALPART(y))) ? BOOL_T : BOOL_F;
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_eqp);
if (INUMP(y)) return BOOL_F;
ASRTGO(NIMP(y) && BIGP(y), bady);
return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F;
}
if (NINUMP(y)) {
# ifndef RECKLESS
if (!(NIMP(y) && BIGP(y)))
bady: wta(y, (char *)ARG2, s_eqp);
# endif
return BOOL_F;
}
# else
ASRTER(INUMP(x), x, ARG1, s_eqp);
ASRTER(INUMP(y), y, ARG2, s_eqp);
# endif
#endif
return ((long)x==(long)y) ? BOOL_T : BOOL_F;
}
SCM lessp(x, y)
SCM x, y;
{
#ifdef FLOATS
if (NINUMP(x)) {
# ifdef BIGDIG
# ifndef RECKLESS
if (!(NIMP(x)))
badx: wta(x, (char *)ARG1, s_lessp);
# endif
if (BIGP(x)) {
if (INUMP(y)) return BIGSIGN(x) ? BOOL_T : BOOL_F;
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return (1==bigcomp(x, y)) ? BOOL_T : BOOL_F;
ASRTGO(REALP(y), bady);
return (1==scm_bigdblcomp(x, REALPART(y))) ? BOOL_T : BOOL_F;
}
ASRTGO(REALP(x), badx);
# else
ASRTER(NIMP(x) && REALP(x), x, ARG1, s_lessp);
# endif
if (INUMP(y)) return (REALPART(x) < ((double)INUM(y))) ? BOOL_T : BOOL_F;
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return (-1==scm_bigdblcomp(y, REALPART(x))) ? BOOL_T : BOOL_F;
ASRTGO(REALP(y), bady);
# else
ASRTGO(NIMP(y) && REALP(y), bady);
# endif
return (REALPART(x) < REALPART(y)) ? BOOL_T : BOOL_F;
}
if (NINUMP(y)) {
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return BIGSIGN(y) ? BOOL_F : BOOL_T;
# ifndef RECKLESS
if (!(REALP(y)))
bady: wta(y, (char *)ARG2, s_lessp);
# endif
# else
# ifndef RECKLESS
if (!(NIMP(y) && REALP(y)))
bady: wta(y, (char *)ARG2, s_lessp);
# endif
# endif
return (((double)INUM(x)) < REALPART(y)) ? BOOL_T : BOOL_F;
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_lessp);
if (INUMP(y)) return BIGSIGN(x) ? BOOL_T : BOOL_F;
ASRTGO(NIMP(y) && BIGP(y), bady);
return (1==bigcomp(x, y)) ? BOOL_T : BOOL_F;
}
if (NINUMP(y)) {
# ifndef RECKLESS
if (!(NIMP(y) && BIGP(y)))
bady: wta(y, (char *)ARG2, s_lessp);
# endif
return BIGSIGN(y) ? BOOL_F : BOOL_T;
}
# else
ASRTER(INUMP(x), x, ARG1, s_lessp);
ASRTER(INUMP(y), y, ARG2, s_lessp);
# endif
#endif
return ((long)x < (long)y) ? BOOL_T : BOOL_F;
}
SCM greaterp(x, y)
SCM x, y;
{
return lessp(y, x);
}
SCM leqp(x, y)
SCM x, y;
{
return BOOL_NOT(lessp(y, x));
}
SCM greqp(x, y)
SCM x, y;
{
return BOOL_NOT(lessp(x, y));
}
SCM zerop(z)
SCM z;
{
#ifdef FLOATS
if (NINUMP(z)) {
# ifdef BIGDIG
ASRTGO(NIMP(z), badz);
if (BIGP(z)) return BOOL_F;
# ifndef RECKLESS
if (!(INEXP(z)))
badz: wta(z, (char *)ARG1, s_zerop);
# endif
# else
ASRTER(NIMP(z) && INEXP(z), z, ARG1, s_zerop);
# endif
return (z==flo0) ? BOOL_T : BOOL_F;
}
#else
# ifdef BIGDIG
if (NINUMP(z)) {
ASRTER(NIMP(z) && BIGP(z), z, ARG1, s_zerop);
return BOOL_F;
}
# else
ASRTER(INUMP(z), z, ARG1, s_zerop);
# endif
#endif
return (z==INUM0) ? BOOL_T: BOOL_F;
}
SCM positivep(x)
SCM x;
{
#ifdef FLOATS
if (NINUMP(x)) {
# ifdef BIGDIG
ASRTGO(NIMP(x), badx);
if (BIGP(x)) return TYP16(x)==tc16_bigpos ? BOOL_T : BOOL_F;
# ifndef RECKLESS
if (!(REALP(x)))
badx: wta(x, (char *)ARG1, s_positivep);
# endif
# else
ASRTER(NIMP(x) && REALP(x), x, ARG1, s_positivep);
# endif
return (REALPART(x) > 0.0) ? BOOL_T : BOOL_F;
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_positivep);
return TYP16(x)==tc16_bigpos ? BOOL_T : BOOL_F;
}
# else
ASRTER(INUMP(x), x, ARG1, s_positivep);
# endif
#endif
return (x > INUM0) ? BOOL_T : BOOL_F;
}
SCM negativep(x)
SCM x;
{
#ifdef FLOATS
if (NINUMP(x)) {
# ifdef BIGDIG
ASRTGO(NIMP(x), badx);
if (BIGP(x)) return TYP16(x)==tc16_bigpos ? BOOL_F : BOOL_T;
# ifndef RECKLESS
if (!(REALP(x)))
badx: wta(x, (char *)ARG1, s_negativep);
# endif
# else
ASRTER(NIMP(x) && REALP(x), x, ARG1, s_negativep);
# endif
return (REALPART(x) < 0.0) ? BOOL_T : BOOL_F;
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_negativep);
return (TYP16(x)==tc16_bigneg) ? BOOL_T : BOOL_F;
}
# else
ASRTER(INUMP(x), x, ARG1, s_negativep);
# endif
#endif
return (x < INUM0) ? BOOL_T : BOOL_F;
}
static char s_exactprob[] = "not representable as inexact";
SCM lmax(x, y)
SCM x, y;
{
#ifdef FLOATS
SCM t;
double z;
#endif
if (UNBNDP(y)) {
#ifndef RECKLESS
if (!(NUMBERP(x)))
badx: wta(x, (char *)ARG1, s_max);
#endif
return x;
}
#ifdef FLOATS
if (NINUMP(x)) {
# ifdef BIGDIG
ASRTGO(NIMP(x), badx);
if (BIGP(x)) {
if (INUMP(y)) return BIGSIGN(x) ? y : x;
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return (1==bigcomp(x, y)) ? y : x;
ASRTGO(REALP(y), bady);
big_dbl:
if (-1 != scm_bigdblcomp(x, REALPART(y))) return y;
z = big2dbl(x);
ASRTER(0==scm_bigdblcomp(x, z), x, s_exactprob, s_max);
return makdbl(z, 0.0);
}
ASRTGO(REALP(x), badx);
# else
ASRTER(NIMP(x) && REALP(x), x, ARG1, s_max);
# endif
if (INUMP(y)) return (REALPART(x) < (z = INUM(y))) ? makdbl(z, 0.0) : x;
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {
t = y; y = x; x = t; goto big_dbl;
}
ASRTGO(REALP(y), bady);
# else
ASRTGO(NIMP(y) && REALP(y), bady);
# endif
return (REALPART(x) < REALPART(y)) ? y : x;
}
if (NINUMP(y)) {
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return BIGSIGN(y) ? x : y;
# ifndef RECKLESS
if (!(REALP(y)))
bady: wta(y, (char *)ARG2, s_max);
# endif
# else
# ifndef RECKLESS
if (!(NIMP(y) && REALP(y)))
bady: wta(y, (char *)ARG2, s_max);
# endif
# endif
return ((z = INUM(x)) < REALPART(y)) ? y : makdbl(z, 0.0);
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_max);
if (INUMP(y)) return BIGSIGN(x) ? y : x;
ASRTGO(NIMP(y) && BIGP(y), bady);
return (1==bigcomp(x, y)) ? y : x;
}
if (NINUMP(y)) {
# ifndef RECKLESS
if (!(NIMP(y) && BIGP(y)))
bady: wta(y, (char *)ARG2, s_max);
# endif
return BIGSIGN(y) ? x : y;
}
# else
ASRTER(INUMP(x), x, ARG1, s_max);
ASRTER(INUMP(y), y, ARG2, s_max);
# endif
#endif
return ((long)x < (long)y) ? y : x;
}
SCM lmin(x, y)
SCM x, y;
{
#ifdef FLOATS
SCM t;
double z;
#endif
if (UNBNDP(y)) {
#ifndef RECKLESS
if (!(NUMBERP(x)))
badx: wta(x, (char *)ARG1, s_min);
#endif
return x;
}
#ifdef FLOATS
if (NINUMP(x)) {
# ifdef BIGDIG
ASRTGO(NIMP(x), badx);
if (BIGP(x)) {
if (INUMP(y)) return BIGSIGN(x) ? x : y;
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return (-1==bigcomp(x, y)) ? y : x;
ASRTGO(REALP(y), bady);
big_dbl:
if (1 != scm_bigdblcomp(x, REALPART(y))) return y;
z = big2dbl(x);
ASRTER(0==scm_bigdblcomp(x, z), x, s_exactprob, s_min);
return makdbl(z, 0.0);
}
ASRTGO(REALP(x), badx);
# else
ASRTER(NIMP(x) && REALP(x), x, ARG1, s_min);
# endif
if (INUMP(y)) return (REALPART(x) > (z = INUM(y))) ? makdbl(z, 0.0) : x;
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {
t = y; y = x; x = t; goto big_dbl;
}
ASRTGO(REALP(y), bady);
# else
ASRTGO(NIMP(y) && REALP(y), bady);
# endif
return (REALPART(x) > REALPART(y)) ? y : x;
}
if (NINUMP(y)) {
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return BIGSIGN(y) ? y : x;
# ifndef RECKLESS
if (!(REALP(y)))
bady: wta(y, (char *)ARG2, s_min);
# endif
# else
# ifndef RECKLESS
if (!(NIMP(y) && REALP(y)))
bady: wta(y, (char *)ARG2, s_min);
# endif
# endif
return ((z = INUM(x)) > REALPART(y)) ? y : makdbl(z, 0.0);
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_min);
if (INUMP(y)) return BIGSIGN(x) ? x : y;
ASRTGO(NIMP(y) && BIGP(y), bady);
return (-1==bigcomp(x, y)) ? y : x;
}
if (NINUMP(y)) {
# ifndef RECKLESS
if (!(NIMP(y) && BIGP(y)))
bady: wta(y, (char *)ARG2, s_min);
# endif
return BIGSIGN(y) ? y : x;
}
# else
ASRTER(INUMP(x), x, ARG1, s_min);
ASRTER(INUMP(y), y, ARG2, s_min);
# endif
#endif
return ((long)x > (long)y) ? y : x;
}
SCM sum(x, y)
SCM x, y;
{
if (UNBNDP(y)) {
if (UNBNDP(x)) return INUM0;
#ifndef RECKLESS
if (!(NUMBERP(x)))
badx: wta(x, (char *)ARG1, s_sum);
#endif
return x;
}
#ifdef FLOATS
if (NINUMP(x)) {
SCM t;
# ifdef BIGDIG
ASRTGO(NIMP(x), badx);
if (BIGP(x)) {
if (INUMP(y)) {t = x; x = y; y = t; goto intbig;}
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {
if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;}
return addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0);
}
ASRTGO(INEXP(y), bady);
bigreal: return makdbl(big2dbl(x)+REALPART(y), CPLXP(y)?IMAG(y):0.0);
}
ASRTGO(INEXP(x), badx);
# else
ASRTGO(NIMP(x) && INEXP(x), badx);
# endif
if (INUMP(y)) {t = x; x = y; y = t; goto intreal;}
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {t = x; x = y; y = t; goto bigreal;}
# ifndef RECKLESS
else if (!(INEXP(y)))
bady: wta(y, (char *)ARG2, s_sum);
# endif
# else
# ifndef RECKLESS
if (!(NIMP(y) && INEXP(y)))
bady: wta(y, (char *)ARG2, s_sum);
# endif
# endif
{
double i = 0.0;
if (CPLXP(x)) i = IMAG(x);
if (CPLXP(y)) i += IMAG(y);
return makdbl(REALPART(x)+REALPART(y), i);
}
}
if (NINUMP(y)) {
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y))
intbig: {
# ifndef DIGSTOOBIG
long z = pseudolong(INUM(x));
return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0);
# else
BIGDIG zdigs[DIGSPERLONG];
longdigs(INUM(x), zdigs);
return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0);
# endif
}
ASRTGO(INEXP(y), bady);
# else
ASRTGO(NIMP(y) && INEXP(y), bady);
# endif
intreal: return makdbl(INUM(x)+REALPART(y), CPLXP(y)?IMAG(y):0.0);
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
SCM t;
ASRTGO(NIMP(x) && BIGP(x), badx);
if (INUMP(y)) {t = x; x = y; y = t; goto intbig;}
ASRTGO(NIMP(y) && BIGP(y), bady);
if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;}
return addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0);
}
if (NINUMP(y)) {
# ifndef RECKLESS
if (!(NIMP(y) && BIGP(y)))
bady: wta(y, (char *)ARG2, s_sum);
# endif
intbig: {
# ifndef DIGSTOOBIG
long z = pseudolong(INUM(x));
return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0);
# else
BIGDIG zdigs[DIGSPERLONG];
longdigs(INUM(x), zdigs);
return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0);
# endif
}
}
# else
ASRTGO(INUMP(x), badx);
ASRTER(INUMP(y), y, ARG2, s_sum);
# endif
#endif
x = INUM(x)+INUM(y);
if (FIXABLE(x)) return MAKINUM(x);
#ifdef BIGDIG
return long2big(x);
#else
# ifdef FLOATS
return makdbl((double)x, 0.0);
# else
wta(y, (char *)OVFLOW, s_sum);
# endif
#endif
}
SCM difference(x, y)
SCM x, y;
{
#ifdef FLOATS
if (NINUMP(x)) {
# ifndef RECKLESS
if (!(NIMP(x)))
badx: wta(x, (char *)ARG1, s_difference);
# endif
if (UNBNDP(y)) {
# ifdef BIGDIG
if (BIGP(x)) {
x = copybig(x, !BIGSIGN(x));
return NUMDIGS(x) * BITSPERDIG/CHAR_BIT <= sizeof(SCM) ?
big2inum(x, NUMDIGS(x)) : x;
}
# endif
ASRTGO(INEXP(x), badx);
return makdbl(-REALPART(x), CPLXP(x)?-IMAG(x):0.0);
}
if (INUMP(y)) return sum(x, MAKINUM(-INUM(y)));
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(x)) {
if (BIGP(y)) return (NUMDIGS(x) < NUMDIGS(y)) ?
addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0x0100) :
addbig(BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ^ 0x0100, x, 0);
ASRTGO(INEXP(y), bady);
return makdbl(big2dbl(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0);
}
ASRTGO(INEXP(x), badx);
if (BIGP(y)) return makdbl(REALPART(x)-big2dbl(y), CPLXP(x)?IMAG(x):0.0);
ASRTGO(INEXP(y), bady);
# else
ASRTGO(INEXP(x), badx);
ASRTGO(NIMP(y) && INEXP(y), bady);
# endif
if (CPLXP(x)) {
if (CPLXP(y))
return makdbl(REAL(x)-REAL(y), IMAG(x)-IMAG(y));
else
return makdbl(REAL(x)-REALPART(y), IMAG(x));
}
return makdbl(REALPART(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0);
}
if (UNBNDP(y)) {x = -INUM(x); goto checkx;}
if (NINUMP(y)) {
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {
# ifndef DIGSTOOBIG
long z = pseudolong(INUM(x));
return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100);
# else
BIGDIG zdigs[DIGSPERLONG];
longdigs(INUM(x), zdigs);
return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100);
# endif
}
# ifndef RECKLESS
if (!(INEXP(y)))
bady: wta(y, (char *)ARG2, s_difference);
# endif
# else
# ifndef RECKLESS
if (!(NIMP(y) && INEXP(y)))
bady: wta(y, (char *)ARG2, s_difference);
# endif
# endif
return makdbl(INUM(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0);
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_difference);
if (UNBNDP(y)) {
x = copybig(x, !BIGSIGN(x));
return NUMDIGS(x) * BITSPERDIG/CHAR_BIT <= sizeof(SCM) ?
big2inum(x, NUMDIGS(x)) : x;
}
if (INUMP(y)) {
# ifndef DIGSTOOBIG
long z = pseudolong(INUM(y));
return addbig((BIGDIG *)&z, DIGSPERLONG, (y < 0) ? 0 : 0x0100, x, 0);
# else
BIGDIG zdigs[DIGSPERLONG];
longdigs(INUM(x), zdigs);
return addbig(zdigs, DIGSPERLONG, (y < 0) ? 0 : 0x0100, x, 0);
# endif
}
ASRTGO(NIMP(y) && BIGP(y), bady);
return (NUMDIGS(x) < NUMDIGS(y)) ?
addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0x0100) :
addbig(BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ^ 0x0100, x, 0);
}
if (UNBNDP(y)) {x = -INUM(x); goto checkx;}
if (NINUMP(y)) {
# ifndef RECKLESS
if (!(NIMP(y) && BIGP(y)))
bady: wta(y, (char *)ARG2, s_difference);
# endif
{
# ifndef DIGSTOOBIG
long z = pseudolong(INUM(x));
return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100);
# else
BIGDIG zdigs[DIGSPERLONG];
longdigs(INUM(x), zdigs);
return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100);
# endif
}
}
# else
ASRTER(INUMP(x), x, ARG1, s_difference);
if (UNBNDP(y)) {x = -INUM(x); goto checkx;}
ASRTER(INUMP(y), y, ARG2, s_difference);
# endif
#endif
x = INUM(x)-INUM(y);
checkx:
if (FIXABLE(x)) return MAKINUM(x);
#ifdef BIGDIG
return long2big(x);
#else
# ifdef FLOATS
return makdbl((double)x, 0.0);
# else
wta(y, (char *)OVFLOW, s_difference);
# endif
#endif
}
SCM product(x, y)
SCM x, y;
{
if (UNBNDP(y)) {
if (UNBNDP(x)) return MAKINUM(1L);
#ifndef RECKLESS
if (!(NUMBERP(x)))
badx: wta(x, (char *)ARG1, s_product);
#endif
return x;
}
#ifdef FLOATS
if (NINUMP(x)) {
SCM t;
# ifdef BIGDIG
ASRTGO(NIMP(x), badx);
if (BIGP(x)) {
if (INUMP(y)) {t = x; x = y; y = t; goto intbig;}
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return mulbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y),
BIGSIGN(x) ^ BIGSIGN(y));
ASRTGO(INEXP(y), bady);
bigreal:
return bigdblop('*', x, REALPART(y), CPLXP(y) ? IMAG(y) : 0.0);
}
ASRTGO(INEXP(x), badx);
# else
ASRTGO(NIMP(x) && INEXP(x), badx);
# endif
if (INUMP(y)) {t = x; x = y; y = t; goto intreal;}
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {t = x; x = y; y = t; goto bigreal;}
# ifndef RECKLESS
else if (!(INEXP(y)))
bady: wta(y, (char *)ARG2, s_product);
# endif
# else
# ifndef RECKLESS
if (!(NIMP(y) && INEXP(y)))
bady: wta(y, (char *)ARG2, s_product);
# endif
# endif
if (CPLXP(x)) {
if (CPLXP(y))
return makdbl(REAL(x)*REAL(y)-IMAG(x)*IMAG(y),
REAL(x)*IMAG(y)+IMAG(x)*REAL(y));
else
return makdbl(REAL(x)*REALPART(y), IMAG(x)*REALPART(y));
}
return makdbl(REALPART(x)*REALPART(y),
CPLXP(y)?REALPART(x)*IMAG(y):0.0);
}
if (NINUMP(y)) {
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {
intbig: if (INUM0==x) return x; if (MAKINUM(1L)==x) return y;
{
# ifndef DIGSTOOBIG
long z = pseudolong(INUM(x));
return mulbig((BIGDIG *)&z, DIGSPERLONG, BDIGITS(y), NUMDIGS(y),
BIGSIGN(y) ? (x>0) : (x<0));
# else
BIGDIG zdigs[DIGSPERLONG];
longdigs(INUM(x), zdigs);
return mulbig(zdigs, DIGSPERLONG, BDIGITS(y), NUMDIGS(y),
BIGSIGN(y) ? (x>0) : (x<0));
# endif
}
}
ASRTGO(INEXP(y), bady);
# else
ASRTGO(NIMP(y) && INEXP(y), bady);
# endif
intreal: return makdbl(INUM(x)*REALPART(y), CPLXP(y)?INUM(x)*IMAG(y):0.0);
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
ASRTGO(NIMP(x) && BIGP(x), badx);
if (INUMP(y)) {SCM t = x; x = y; y = t; goto intbig;}
ASRTGO(NIMP(y) && BIGP(y), bady);
return mulbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y),
BIGSIGN(x) ^ BIGSIGN(y));
}
if (NINUMP(y)) {
# ifndef RECKLESS
if (!(NIMP(y) && BIGP(y)))
bady: wta(y, (char *)ARG2, s_product);
# endif
intbig: if (INUM0==x) return x; if (MAKINUM(1L)==x) return y;
{
# ifndef DIGSTOOBIG
long z = pseudolong(INUM(x));
return mulbig((BIGDIG *)&z, DIGSPERLONG, BDIGITS(y), NUMDIGS(y),
BIGSIGN(y) ? (x>0) : (x<0));
# else
BIGDIG zdigs[DIGSPERLONG];
longdigs(INUM(x), zdigs);
return mulbig(zdigs, DIGSPERLONG, BDIGITS(y), NUMDIGS(y),
BIGSIGN(y) ? (x>0) : (x<0));
# endif
}
}
# else
ASRTGO(INUMP(x), badx);
ASRTER(INUMP(y), y, ARG2, s_product);
# endif
#endif
{
long i, j, k;
i = INUM(x);
if (0==i) return x;
j = INUM(y);
k = i * j;
y = MAKINUM(k);
if (k != INUM(y) || k/i != j)
#ifdef BIGDIG
{
int sgn = (i < 0) ^ (j < 0);
# ifndef DIGSTOOBIG
i = pseudolong(i);
j = pseudolong(j);
return mulbig((BIGDIG *)&i, DIGSPERLONG,
(BIGDIG *)&j, DIGSPERLONG, sgn);
# else /* DIGSTOOBIG */
BIGDIG idigs[DIGSPERLONG];
BIGDIG jdigs[DIGSPERLONG];
longdigs(i, idigs);
longdigs(j, jdigs);
return mulbig(idigs, DIGSPERLONG, jdigs, DIGSPERLONG, sgn);
# endif
}
#else
# ifdef FLOATS
return makdbl(((double)i)*((double)j), 0.0);
# else
wta(y, (char *)OVFLOW, s_product);
# endif
#endif
return y;
}
}
/* Use "Smith's formula" to extend dynamic range */
/* David Goldberg
What Every Computer Scientist Should Know About Floating-Point Arithmetic
http://cch.loria.fr/documentation/IEEE754/ACM/goldberg.pdf */
SCM divide(x, y)
SCM x, y;
{
#ifdef FLOATS
double den, a = 1.0;
if (NINUMP(x)) {
# ifndef RECKLESS
if (!(NIMP(x)))
badx: wta(x, (char *)ARG1, s_divide);
# endif
if (UNBNDP(y)) {
# ifdef BIGDIG
if (BIGP(x)) return makdbl(1.0/big2dbl(x), 0.0);
# endif
/* reciprocal */
ASRTGO(INEXP(x), badx);
if (REALP(x)) return makdbl(1.0/REALPART(x), 0.0);
{
y = x;
a = 1.0;
goto real_over_complex;
}
}
# ifdef BIGDIG
if (BIGP(x)) {
SCM z;
if (INUMP(y)) {
z = INUM(y);
ASRTER(z, y, OVFLOW, s_divide);
if (1==z) return x;
if (z < 0) z = -z;
if (z < BIGRAD) {
SCM w = copybig(x, BIGSIGN(x) ? (y>0) : (y<0));
return divbigdig(BDIGITS(w), NUMDIGS(w), (BIGDIG)z) ?
bigdblop('/', x, INUM(y), 0.0) : normbig(w);
}
# ifndef DIGSTOOBIG
z = pseudolong(z);
z = divbigbig(BDIGITS(x), NUMDIGS(x), (BIGDIG *)&z, DIGSPERLONG,
BIGSIGN(x) ? (y>0) : (y<0), 3);
# else
{
BIGDIG zdigs[DIGSPERLONG];
longdigs(z, zdigs);
z = divbigbig(BDIGITS(x), NUMDIGS(x), zdigs, DIGSPERLONG,
BIGSIGN(x) ? (y>0) : (y<0), 3);
}
# endif
return z ? z : bigdblop('/', x, INUM(y), 0.0);
}
ASRTGO(NIMP(y), bady);
if (BIGP(y)) {
z = divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y),
BIGSIGN(x) ^ BIGSIGN(y), 3);
return z ? z : inex_divbigbig(x, y);
}
ASRTGO(INEXP(y), bady);
return bigdblop('/', x, REALPART(y), CPLXP(y) ? IMAG(y) : 0.0);
}
# endif
ASRTGO(INEXP(x), badx);
if (INUMP(y)) {den = INUM(y); goto basic_div;}
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return bigdblop('\\', y, REALPART(x), CPLXP(x) ? IMAG(x) : 0.0);
ASRTGO(INEXP(y), bady);
# else
ASRTGO(NIMP(y) && INEXP(y), bady);
# endif
if (REALP(y)) {
den = REALPART(y);
basic_div: return makdbl(REALPART(x)/den, CPLXP(x)?IMAG(x)/den:0.0);
}
a = REALPART(x);
if (REALP(x)) goto real_over_complex;
/* Both x and y are complex */
/* Use "Smith's formula" to extend dynamic range */
{
double b = IMAG(x);
double c = REALPART(y);
double d = IMAG(y);
if ((d > 0 ? d : -d) < (c > 0 ? c : -c)) {
double r = d/c;
double i = c + d*r;
return makdbl((a + b*r)/i, (b - a*r)/i);
}
{
double r = c/d;
double i = d + c*r;
return makdbl((b + a*r)/i, (-a + b*r)/i);
}
}
}
if (UNBNDP(y)) {
if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x;
return makdbl(1.0/((double)INUM(x)), 0.0);
}
if (NINUMP(y)) {
# ifdef BIGDIG
ASRTGO(NIMP(y), bady);
if (BIGP(y)) return bigdblop('\\', y, INUM(x), 0.0);
# ifndef RECKLESS
if (!(INEXP(y)))
bady: wta(y, (char *)ARG2, s_divide);
# endif
# else
# ifndef RECKLESS
if (!(NIMP(y) && INEXP(y)))
bady: wta(y, (char *)ARG2, s_divide);
# endif
# endif
if (REALP(y)) return makdbl(INUM(x)/REALPART(y), 0.0);
a = INUM(x);
real_over_complex:
/* Both x and y are complex */
/* Use "Smith's formula" to extend dynamic range */
{
double c = REALPART(y);
double d = IMAG(y);
if ((d > 0 ? d : -d) < (c > 0 ? c : -c)) {
double r = d/c;
double i = c + d*r;
return makdbl((a)/i, (- a*r)/i);
}
{
double r = c/d;
double i = d + c*r;
return makdbl((a*r)/i, (-a)/i);
}
}
}
#else
# ifdef BIGDIG
if (NINUMP(x)) {
SCM z;
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_divide);
if (UNBNDP(y)) goto ov;
if (INUMP(y)) {
z = INUM(y);
if (!z) goto ov;
if (1==z) return x;
if (z < 0) z = -z;
if (z < BIGRAD) {
SCM w = copybig(x, BIGSIGN(x) ? (y>0) : (y<0));
if (divbigdig(BDIGITS(w), NUMDIGS(w), (BIGDIG)z)) goto ov;
return w;
}
# ifndef DIGSTOOBIG
z = pseudolong(z);
z = divbigbig(BDIGITS(x), NUMDIGS(x), (BIGDIG *)&z, DIGSPERLONG,
BIGSIGN(x) ? (y>0) : (y<0), 3);
# else
{
BIGDIG zdigs[DIGSPERLONG];
longdigs(z, zdigs);
z = divbigbig(BDIGITS(x), NUMDIGS(x), zdigs, DIGSPERLONG,
BIGSIGN(x) ? (y>0) : (y<0), 3);
}
# endif
} else {
ASRTGO(NIMP(y) && BIGP(y), bady);
z = divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y),
BIGSIGN(x) ^ BIGSIGN(y), 3);
}
if (!z) goto ov;
return z;
}
if (UNBNDP(y)) {
if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x;
goto ov;
}
if (NINUMP(y)) {
# ifndef RECKLESS
if (!(NIMP(y) && BIGP(y)))
bady: wta(y, (char *)ARG2, s_divide);
# endif
goto ov;
}
# else
ASRTER(INUMP(x), x, ARG1, s_divide);
if (UNBNDP(y)) {
if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x;
goto ov;
}
ASRTER(INUMP(y), y, ARG2, s_divide);
# endif
#endif
{
long z = INUM(y);
if ((0==z) || INUM(x)%z) goto ov;
z = INUM(x)/z;
if (FIXABLE(z)) return MAKINUM(z);
#ifdef BIGDIG
return long2big(z);
#endif
#ifdef FLOATS
ov: return makdbl(((double)INUM(x))/((double)INUM(y)), 0.0);
#else
ov: wta(x, (char *)OVFLOW, s_divide);
#endif
}
}
SCM scm_intexpt(z1, z2)
SCM z1, z2;
{
SCM acc = MAKINUM(1L);
int recip = 0;
#ifdef FLOATS
double dacc, dz1;
#endif
if (INUM0==z2) return sum(acc, product(z1, INUM0));
ASRTER(INUMP(z2), z2, ARG2, s_intexpt);
if (acc==z1) return z1;
if (MAKINUM(-1L)==z1) return BOOL_F==evenp(z2)?z1:acc;
z2 = INUM(z2);
if (z2 < 0) {
z2 = -z2;
recip = 1; /* z1 = divide(z1, UNDEFINED); */
}
if (INUMP(z1)) {
long tmp, iacc = 1, iz1 = INUM(z1);
#ifdef FLOATS
if (recip) { dz1 = iz1; goto flocase; }
#endif
while (1) {
if (0==z2) {
acc = long2num(iacc);
break;
}
if (0==iz1)
if (0==recip) return z1;
else goto overflow;
if (1==z2) {
tmp = iacc*iz1;
if (tmp/iacc != iz1) {
overflow:
z1 = long2num(iz1);
acc = long2num(iacc);
ASRTGO(NFALSEP(z1) && NFALSEP(acc), errout);
goto gencase;
}
acc = long2num(tmp);
break;
}
if (z2 & 1) {
tmp = iacc*iz1;
if (tmp/iacc != iz1) goto overflow;
iacc = tmp;
z2 = z2 - 1; /* so jumping to gencase works */
}
tmp = iz1*iz1;
if (tmp/iz1 != iz1) goto overflow;
iz1 = tmp;
z2 >>= 1;
}
#ifndef RECKLESS
if (FALSEP(acc))
errout: wta(UNDEFINED, (char *)OVFLOW, s_intexpt);
#endif
goto ret;
}
ASRTER(NIMP(z1), z1, ARG1, s_intexpt);
#ifdef FLOATS
if (REALP(z1)) {
dz1 = REALPART(z1);
flocase:
dacc = 1.0;
while(1) {
if (0==z2) break;
if (1==z2) {dacc = dacc*dz1; break;}
if (z2 & 1) dacc = dacc*dz1;
dz1 = dz1*dz1;
z2 >>= 1;
}
return makdbl(recip ? 1.0/dacc : dacc, 0.0);
}
#endif
gencase:
while(1) {
if (0==z2) break;
if (1==z2) {acc = product(acc, z1); break;}
if (z2 & 1) acc = product(acc, z1);
z1 = product(z1, z1);
z2 >>= 1;
}
ret: return recip ? divide(acc, UNDEFINED) : acc;
}
#ifdef FLOATS
# ifndef HAVE_ATANH
double asinh(x)
double x;
{
return log(x+sqrt(x*x+1));
}
double acosh(x)
double x;
{
return log(x+sqrt(x*x-1));
}
double atanh(x)
double x;
{
return 0.5*log((1+x)/(1-x));
}
# endif
double scm_truncate(x)
double x;
{
if (x < 0.0) return -floor(-x);
return floor(x);
}
double scm_round(x)
double x;
{
double plus_half = x + 0.5;
double result = floor(plus_half);
/* Adjust so that the round is towards even. */
return (plus_half==result && plus_half / 2 != floor(plus_half / 2))
? result - 1 : result;
}
struct dpair {double x, y;};
void two_doubles(z1, z2, sstring, xy)
SCM z1, z2;
char *sstring;
struct dpair *xy;
{
if (INUMP(z1)) xy->x = INUM(z1);
else {
# ifdef BIGDIG
ASRTGO(NIMP(z1), badz1);
if (BIGP(z1)) xy->x = big2dbl(z1);
else {
# ifndef RECKLESS
if (!(REALP(z1)))
badz1: wta(z1, (char *)ARG1, sstring);
# endif
xy->x = REALPART(z1);}
# else
{ASRTER(NIMP(z1) && REALP(z1), z1, ARG1, sstring);
xy->x = REALPART(z1);}
# endif
}
if (INUMP(z2)) xy->y = INUM(z2);
else {
# ifdef BIGDIG
ASRTGO(NIMP(z2), badz2);
if (BIGP(z2)) xy->y = big2dbl(z2);
else {
# ifndef RECKLESS
if (!(REALP(z2)))
badz2: wta(z2, (char *)ARG2, sstring);
# endif
xy->y = REALPART(z2);}
# else
{
ASRTER(NIMP(z2) && REALP(z2), z2, ARG2, sstring);
xy->y = REALPART(z2);
}
# endif
}
}
SCM expt(z1, z2)
SCM z1, z2;
{
struct dpair xy;
two_doubles(z1, z2, s_expt, &xy);
return makdbl(pow(xy.x, xy.y), 0.0);
}
SCM latan2(z1, z2)
SCM z1, z2;
{
struct dpair xy;
two_doubles(z1, z2, s_atan2, &xy);
return makdbl(atan2(xy.x, xy.y), 0.0);
}
SCM makrect(z1, z2)
SCM z1, z2;
{
struct dpair xy;
two_doubles(z1, z2, s_makrect, &xy);
return makdbl(xy.x, xy.y);
}
SCM makpolar(z1, z2)
SCM z1, z2;
{
struct dpair xy;
two_doubles(z1, z2, s_makpolar, &xy);
return makdbl(xy.x*cos(xy.y), xy.x*sin(xy.y));
}
SCM real_part(z)
SCM z;
{
if (NINUMP(z)) {
# ifdef BIGDIG
ASRTGO(NIMP(z), badz);
if (BIGP(z)) return z;
# ifndef RECKLESS
if (!(INEXP(z)))
badz: wta(z, (char *)ARG1, s_real_part);
# endif
# else
ASRTER(NIMP(z) && INEXP(z), z, ARG1, s_real_part);
# endif
if (CPLXP(z)) return makdbl(REAL(z), 0.0);
}
return z;
}
SCM imag_part(z)
SCM z;
{
if (INUMP(z)) return INUM0;
# ifdef BIGDIG
ASRTGO(NIMP(z), badz);
if (BIGP(z)) return INUM0;
# ifndef RECKLESS
if (!(INEXP(z)))
badz: wta(z, (char *)ARG1, s_imag_part);
# endif
# else
ASRTER(NIMP(z) && INEXP(z), z, ARG1, s_imag_part);
# endif
if (CPLXP(z)) return makdbl(IMAG(z), 0.0);
return flo0;
}
SCM scm_abs(z)
SCM z;
{
if (INUMP(z)) return scm_iabs(z);
ASRTGO(NIMP(z), badz);
# ifdef BIGDIG
if (BIGP(z)) return scm_iabs(z);
# endif
if (!REALP(z))
badz: wta(z, (char *)ARG1, s_abs);
return makdbl(fabs(REALPART(z)), 0.0);
}
SCM scm_magnitude(z)
SCM z;
{
if (INUMP(z)) return scm_iabs(z);
ASRTGO(NIMP(z), badz);
# ifdef BIGDIG
if (BIGP(z)) return scm_iabs(z);
# endif
if (!INEXP(z))
badz: wta(z, (char *)ARG1, s_magnitude);
if (CPLXP(z))
{
double i = IMAG(z), r = REAL(z);
if (i < 0) i = -i;
if (r < 0) r = -r;
if (i < r) {
double q = i / r;
return makdbl(r * sqrt(1 + q * q), 0.0);
}
if (0.0==i) return i;
{
double q = r / i;
return makdbl(i * sqrt(1 + q * q), 0.0);
}
}
return makdbl(fabs(REALPART(z)), 0.0);
}
SCM angle(z)
SCM z;
{
double x, y = 0.0;
if (INUMP(z)) {x = (z>=INUM0) ? 1.0 : -1.0; goto do_angle;}
# ifdef BIGDIG
ASRTGO(NIMP(z), badz);
if (BIGP(z)) {x = (TYP16(z)==tc16_bigpos) ? 1.0 : -1.0; goto do_angle;}
# ifndef RECKLESS
if (!(INEXP(z))) {
badz: wta(z, (char *)ARG1, s_angle);}
# endif
# else
ASRTER(NIMP(z) && INEXP(z), z, ARG1, s_angle);
# endif
if (REALP(z)) {x = REALPART(z); goto do_angle;}
x = REAL(z); y = IMAG(z);
do_angle:
return makdbl(atan2(y, x), 0.0);
}
SCM ex2in(z)
SCM z;
{
if (INUMP(z)) return makdbl((double)INUM(z), 0.0);
ASRTGO(NIMP(z), badz);
if (INEXP(z)) return z;
# ifdef BIGDIG
if (BIGP(z)) return makdbl(big2dbl(z), 0.0);
# endif
badz: wta(z, (char *)ARG1, s_ex2in);
}
SCM in2ex(z)
SCM z;
{
if (INUMP(z)) return z;
# ifdef BIGDIG
ASRTGO(NIMP(z), badz);
if (BIGP(z)) return z;
# ifndef RECKLESS
if (!(REALP(z)))
badz: wta(z, (char *)ARG1, s_in2ex);
# endif
# else
ASRTER(NIMP(z) && REALP(z), z, ARG1, s_in2ex);
# endif
# ifdef BIGDIG
{
double u = floor(REALPART(z)+0.5);
if ((u <= MOST_POSITIVE_FIXNUM)
# ifdef hpux
&& (-u <= -MOST_NEGATIVE_FIXNUM) /* workaround for HP700 cc bug */
# endif
) {
SCM ans = MAKINUM((long)u);
if (INUM(ans)==(long)u) return ans;
}
ASRTGO(!((u==2*u) || (u)!=(u)), badz); /* problem? */
return dbl2big(u);
}
# else
return MAKINUM((long)floor(REALPART(z)+0.5));
# endif
}
#else /* ~FLOATS */
static char s_trunc[] = "truncate";
SCM numident(x)
SCM x;
{
# ifdef BIGDIG
ASRTER(INUMP(x) || (NIMP(x) && BIGP(x)), x, ARG1, s_trunc);
# else
ASRTER(INUMP(x), x, ARG1, s_trunc);
# endif
return x;
}
#endif /* FLOATS */
SCM scm_iabs(x)
SCM x;
{
#ifdef BIGDIG
if (NINUMP(x)) {
ASRTER(NIMP(x) && BIGP(x), x, ARG1, s_abs);
if (TYP16(x)==tc16_bigpos) return x;
return copybig(x, 0);
}
#else
ASRTER(INUMP(x), x, ARG1, s_abs);
#endif
if (INUM(x) >= 0) return x;
x = -INUM(x);
if (!POSFIXABLE(x))
#ifdef BIGDIG
return long2big(x);
#else
wta(MAKINUM(-x), (char *)OVFLOW, s_abs);
#endif
return MAKINUM(x);
}
#ifdef BIGDIG
# ifdef FLOATS
SCM dbl2big(d)
double d; /* must be integer */
{
sizet i = 0;
long c;
BIGDIG *digits;
SCM ans;
double u = (d < 0)?-d:d;
while (0 != floor(u)) {u /= BIGRAD;i++;}
ans = mkbig(i, d < 0);
digits = BDIGITS(ans);
while (i--) {
u *= BIGRAD;
c = floor(u);
u -= c;
digits[i] = c;
}
ASRTER(0==u, INUM0, OVFLOW, "dbl2big");
return ans;
}
double big2dbl(b)
SCM b;
{
double ans = 0.0;
sizet i = NUMDIGS(b);
BIGDIG *digits = BDIGITS(b);
while (i--) ans = digits[i] + BIGRAD*ans;
if (tc16_bigneg==TYP16(b)) return -ans;
return ans;
}
static double big2scaldbl(b, expt)
SCM b;
int expt;
{
double ans = 0.0;
int i = NUMDIGS(b) - 1;
BIGDIG *digits = BDIGITS(b);
while (i > (expt/BITSPERDIG)) {
ans = digits[i] + BIGRAD*ans;
i--;
}
ans = ldexp(ans, BITSPERDIG - expt);
/*
if (expt = (expt % BITSPERDIG)) {
ans = (digits[i] >> expt) +
(1L << (BITSPERDIG - expt))*ans;
}
if ((1L << (BITSPERDIG - expt - 1)) & digits[i])
ans += 1;
*/
if (tc16_bigneg==TYP16(b)) return -ans;
return ans;
}
static SCM bigdblop(op, b, re, im)
int op;
SCM b;
double re, im;
{
double bm = 0.0;
int i = 0;
if (NUMDIGS(b)*BITSPERDIG < DBL_MAX_EXP) {
bm = big2dbl(b);
}
else {
i = INUM(scm_intlength(b));
if (i < DBL_MAX_EXP) {
i = 0;
bm = big2dbl(b);
}
else {
i = i + 1 - DBL_MAX_EXP;
bm = big2scaldbl(b, i);
}
}
switch (op) {
case '*':
return makdbl(ldexp(bm*re, i), 0.0==im ? 0.0 : ldexp(bm*im, i));
case '/': {
double d = re*re + im*im;
return makdbl(ldexp(bm*(re/d), i), ldexp(-bm*(im/d), i));
}
case '\\':
return makdbl(ldexp(re/bm, -i), 0.0==im ? 0.0 : ldexp(im/bm, -i));
default:
return UNSPECIFIED;
}
}
static SCM inex_divbigbig(a, b)
SCM a, b;
{
double r;
if ((NUMDIGS(a)*BITSPERDIG < DBL_MAX_EXP) &&
(NUMDIGS(b)*BITSPERDIG < DBL_MAX_EXP))
r = big2dbl(a) / big2dbl(b);
else {
int i = INUM(scm_intlength(a));
int j = INUM(scm_intlength(b));
i = (i > j) ? i : j;
if (i < DBL_MAX_EXP)
r = big2dbl(a) / big2dbl(b);
else {
i = i + 1 - DBL_MAX_EXP;
r = big2scaldbl(a, i) / big2scaldbl(b, i);
}
}
return makdbl(r, 0.0);
}
static char s_dfloat_parts[] = "double-float-parts";
SCM scm_dfloat_parts(f)
SCM f;
{
int expt, ndig = dbl_mant_dig;
double mant = frexp(num2dbl(f, (char *)ARG1, s_dfloat_parts), &expt);
# ifdef DBL_MIN_EXP
if (expt < DBL_MIN_EXP)
ndig -= DBL_MIN_EXP - expt;
# endif
mant *= ldexp(1.0, ndig);
expt -= ndig;
return scm_values(dbl2big(mant), MAKINUM(expt), EOL, s_dfloat_parts);
}
static char s_make_dfloat[] = "make-double-float";
SCM scm_make_dfloat(mant, expt)
SCM mant, expt;
{
double dmant = num2dbl(mant, (char *)ARG1, s_make_dfloat);
int e = INUM(expt);
ASRTER(INUMP(expt), expt, ARG2, s_make_dfloat);
ASRTER((dmant < 0 ? -dmant : dmant)<=max_dbl_int, mant,
OUTOFRANGE, s_make_dfloat);
return makdbl(ldexp(dmant, e), 0.0);
}
static char s_next_dfloat[] = "next-double-float";
SCM scm_next_dfloat(f1, f2)
SCM f1, f2;
{
int e, neg = 0;
double d1 = num2dbl(f1, (char *)ARG1, s_next_dfloat);
double dif = num2dbl(f2, (char *)ARG2, s_next_dfloat) - d1;
double d = frexp(d1, &e), eps = dbl_eps;
if (d1 < 0) {neg = 1; dif = -dif; d = -d;}
if (dif > 0) {
# ifdef DBL_MIN_EXP
if (e < DBL_MIN_EXP)
eps = ldexp(eps, DBL_MIN_EXP - e);
else if (0.0==d)
eps = ldexp(1.0, DBL_MIN_EXP - dbl_mant_dig);
# endif
d = ldexp(d + eps, e);
}
else if (dif < 0) {
# ifdef DBL_MIN_EXP
if (e < DBL_MIN_EXP)
eps = ldexp(eps, DBL_MIN_EXP - e);
else if (0.0==d)
eps = ldexp(-1.0, DBL_MIN_EXP - dbl_mant_dig);
# endif
if (0.5==d) eps *= 0.5;
d = ldexp(d - eps, e);
}
else if (0.0==dif)
return f1;
return makdbl(neg ? -d : d, 0.0);
}
# endif
#endif
unsigned long hasher(obj, n, d)
SCM obj;
unsigned long n;
sizet d;
{
switch (7 & PTR2INT(obj)) {
case 2: case 6: /* INUMP(obj) */
return INUM(obj) % n;
case 4:
if (ICHRP(obj))
return (unsigned)(downcase[ICHR(obj)]) % n;
switch ((int) obj) {
#ifndef SICP
case (int) EOL: d = 256; break;
#endif
case (int) BOOL_T: d = 257; break;
case (int) BOOL_F: d = 258; break;
case (int) EOF_VAL: d = 259; break;
default: d = 263; /* perhaps should be error */
}
return d % n;
default: return 263 % n; /* perhaps should be error */
case 0:
switch TYP7(obj) {
default: return 263 % n;
case tc7_smob:
switch TYP16(obj) {
case tcs_bignums:
bighash: return INUM(modulo(obj, MAKINUM(n)));
default: return 263 % n;
#ifdef FLOATS
case tc16_flo:
if (REALP(obj)) {
double r = REALPART(obj);
if (floor(r)==r) {
obj = in2ex(obj);
if (IMP(obj)) return INUM(obj) % n;
goto bighash;
}
}
obj = number2string(obj, MAKINUM(10));
#endif
}
case tcs_symbols: case tc7_string:
return strhash(UCHARS(obj), (sizet) LENGTH(obj), n);
case tc7_vector: {
sizet len = LENGTH(obj);
SCM *data = VELTS(obj);
if (len>5) {
sizet i = d/2;
unsigned long h = 1;
while (i--) h = ((h<<8) + (hasher(data[h % len], n, 2))) % n;
return h;
}
else {
sizet i = len;
unsigned long h = (n)-1;
while (i--) h = ((h<<8) + (hasher(data[i], n, d/len))) % n;
return h;
}
}
case tcs_cons_imcar: case tcs_cons_nimcar:
if (d) return (hasher(CAR(obj), n, d/2)+hasher(CDR(obj), n, d/2)) % n;
else return 1;
case tc7_port:
return ((RDNG & CAR(obj)) ? 260 : 261) % n;
case tcs_closures: case tc7_contin: case tcs_subrs:
return 262 % n;
}
}
}
static char s_hashv[] = "hashv", s_hashq[] = "hashq";
extern char s_obunhash[];
#define s_hash (&s_obunhash[9])
SCM hash(obj, n)
SCM obj;
SCM n;
{
ASRTER(INUMP(n) && 0 <= n, n, ARG2, s_hash);
return MAKINUM(hasher(obj, INUM(n), 10));
}
SCM hashv(obj, n)
SCM obj;
SCM n;
{
ASRTER(INUMP(n) && 0 <= n, n, ARG2, s_hashv);
if (ICHRP(obj)) return MAKINUM((unsigned)(downcase[ICHR(obj)]) % INUM(n));
if (NIMP(obj) && NUMP(obj)) return MAKINUM(hasher(obj, INUM(n), 10));
else return MAKINUM(obj % INUM(n));
}
SCM hashq(obj, n)
SCM obj;
SCM n;
{
ASRTER(INUMP(n) && 0 <= n, n, ARG2, s_hashq);
return MAKINUM((((unsigned) obj) >> 1) % INUM(n));
}
static iproc subr1s[] = {
{"number?", numberp},
{s_inexactp, inexactp},
#ifdef FLOATS
{"complex?", scm_complex_p},
{"real?", realp},
{"rational?", scm_rationalp},
{"integer?", intp},
{s_real_part, real_part},
{s_imag_part, imag_part},
{s_magnitude, scm_magnitude},
{s_angle, angle},
{s_in2ex, in2ex},
{s_ex2in, ex2in},
{s_abs, scm_abs},
# ifdef BIGDIG
{s_dfloat_parts, scm_dfloat_parts},
# endif
#else
{"complex?", numberp},
{"real?", numberp},
{"rational?", numberp},
{"integer?", exactp},
{"floor", numident},
{"ceiling", numident},
{s_trunc, numident},
{"round", numident},
{s_abs, scm_iabs},
#endif
{s_zerop, zerop},
{s_positivep, positivep},
{s_negativep, negativep},
{s_str2list, string2list},
{"list->string", string},
{s_st_copy, string_copy},
{"list->vector", vector},
{s_vect2list, vector2list},
{0, 0}};
static iproc asubrs[] = {
{s_difference, difference},
{s_divide, divide},
{s_max, lmax},
{s_min, lmin},
{s_sum, sum},
{s_product, product},
{0, 0}};
static iproc subr2s[] = {
#ifdef FLOATS
{s_makrect, makrect},
{s_makpolar, makpolar},
{s_atan2, latan2},
{s_expt, expt},
# ifdef BIGDIG
{s_make_dfloat, scm_make_dfloat},
{s_next_dfloat, scm_next_dfloat},
# endif
#endif
#ifdef INUMS_ONLY
{s_memv, memq},
{s_assv, assq},
#else
{s_memv, memv},
{s_assv, assv},
#endif
{s_intexpt, scm_intexpt},
{s_list_tail, list_tail},
{s_ve_fill, vector_fill},
{s_st_fill, string_fill},
{s_hash, hash},
{s_hashv, hashv},
{s_hashq, hashq},
{0, 0}};
static iproc subr2os[] = {
{s_str2number, string2number},
{s_number2string, number2string},
{0, 0}};
static iproc rpsubrs[] = {
#ifdef INUMS_ONLY
{"eqv?", eq},
#else
{"eqv?", eqv},
#endif
{s_eqp, eqp},
{s_lessp, lessp},
{s_grp, greaterp},
{s_leqp, leqp},
{s_greqp, greqp},
{0, 0}};
#ifdef FLOATS
static dblproc cxrs[] = {
{"floor", floor},
{"ceiling", ceil},
{"truncate", scm_truncate},
{"round", scm_round},
{"$abs", fabs},
{"real-sqrt", sqrt},
{"real-exp", exp},
{"real-ln", log},
{"real-log10", log10},
{"real-sin", sin},
{"real-cos", cos},
{"real-tan", tan},
{"real-asin", asin},
{"real-acos", acos},
{"real-atan", atan},
{"real-sinh", sinh},
{"real-cosh", cosh},
{"real-tanh", tanh},
{"real-asinh", asinh},
{"real-acosh", acosh},
{"real-atanh", atanh},
{0, 0}};
#endif
#ifdef FLOATS
static void safe_add_1(f, fsum)
double f, *fsum;
{
*fsum = f + 1.0;
}
#endif
void init_scl()
{
init_iprocs(subr1s, tc7_subr_1);
init_iprocs(subr2os, tc7_subr_2o);
init_iprocs(subr2s, tc7_subr_2);
init_iprocs(asubrs, tc7_asubr);
init_iprocs(rpsubrs, tc7_rpsubr);
#ifdef SICP
add_feature("sicp");
#endif
#ifdef FLOATS
init_iprocs((iproc *)cxrs, tc7_cxr);
# ifdef SINGLES
NEWCELL(flo0);
CAR(flo0) = tc_flo;
FLO(flo0) = 0.0;
# else
DEFER_INTS;
flo0 = must_malloc_cell(1L*sizeof(double), (SCM)tc_dblr, "real");
REAL(flo0) = 0.0;
ALLOW_INTS;
# endif
# ifndef _MSC_VER
DEFER_INTS;
scm_narn = must_malloc_cell(2L*sizeof(double), (SCM)tc_dblc, "complex");
REAL(scm_narn) = 0.0/0.0;
IMAG(scm_narn) = 0.0/0.0;
ALLOW_INTS;
# endif
# ifdef DBL_DIG
dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG;
# else
{ /* determine floating point precision */
double f = 0.1;
volatile double fsum = 1.0+f;
while (fsum != 1.0) {
f /= 10.0;
if (++dblprec > 20) break;
safe_add_1(f, &fsum);
}
dblprec = dblprec-1;
}
# endif /* DBL_DIG */
# ifdef DBL_MANT_DIG
dbl_mant_dig = DBL_MANT_DIG;
# else
{ /* means we #defined it. */
volatile double fsum = 0.0;
double eps = 1.0;
int i = 0;
while (fsum != 1.0) {
eps = 0.5 * eps;
safe_add_1(eps, &fsum);
i++;
}
dbl_mant_dig = i;
}
# endif /* DBL_MANT_DIG */
max_dbl_int = pow(2.0, dbl_mant_dig - 1.0);
max_dbl_int = max_dbl_int + (max_dbl_int - 1.0);
dbl_eps = ldexp(1.0, - dbl_mant_dig);
sysintern("double-float-mantissa-length", MAKINUM(dbl_mant_dig));
#endif
}