2003-08-30 12:47:54 -04:00
|
|
|
/* math.c: Generic math functions.
|
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright 1990, 1991, 1992, 1993, 1994, 1995, Oliver Laumann, Berlin
|
|
|
|
* Copyright 2002, 2003 Sam Hocevar <sam@zoy.org>, Paris
|
|
|
|
*
|
|
|
|
* This software was derived from Elk 1.2, which was Copyright 1987, 1988,
|
|
|
|
* 1989, Nixdorf Computer AG and TELES GmbH, Berlin (Elk 1.2 has been written
|
|
|
|
* by Oliver Laumann for TELES Telematic Services, Berlin, in a joint project
|
|
|
|
* between TELES and Nixdorf Microprocessor Engineering, Berlin).
|
|
|
|
*
|
|
|
|
* Oliver Laumann, TELES GmbH, Nixdorf Computer AG and Sam Hocevar, as co-
|
|
|
|
* owners or individual owners of copyright in this software, grant to any
|
|
|
|
* person or company a worldwide, royalty free, license to
|
|
|
|
*
|
|
|
|
* i) copy this software,
|
|
|
|
* ii) prepare derivative works based on this software,
|
|
|
|
* iii) distribute copies of this software or derivative works,
|
|
|
|
* iv) perform this software, or
|
|
|
|
* v) display this software,
|
|
|
|
*
|
|
|
|
* provided that this notice is not removed and that neither Oliver Laumann
|
|
|
|
* nor Teles nor Nixdorf are deemed to have made any representations as to
|
|
|
|
* the suitability of this software for any purpose nor are held responsible
|
|
|
|
* for any defects of this software.
|
|
|
|
*
|
|
|
|
* THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
|
2003-08-19 15:19:38 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
2003-08-19 15:24:23 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
2003-08-19 15:19:38 -04:00
|
|
|
|
|
|
|
#include "kernel.h"
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
extern int Bignum_To_Integer (Object);
|
2003-08-19 15:19:38 -04:00
|
|
|
|
|
|
|
Object Generic_Multiply(), Generic_Divide();
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
void Init_Math () {
|
2003-08-25 10:17:09 -04:00
|
|
|
#ifdef HAVE_RANDOM
|
2003-08-19 15:19:38 -04:00
|
|
|
srandom (getpid ());
|
|
|
|
#else
|
|
|
|
srand (getpid ());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Make_Integer (register int n) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object num;
|
|
|
|
|
|
|
|
SET(num, T_Fixnum, n);
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Make_Unsigned (register unsigned int n) {
|
2003-08-19 15:19:38 -04:00
|
|
|
if (UFIXNUM_FITS(n))
|
2003-09-02 04:12:11 -04:00
|
|
|
return Make_Integer (n);
|
2003-08-19 15:19:38 -04:00
|
|
|
else
|
2003-09-02 04:12:11 -04:00
|
|
|
return Unsigned_To_Bignum (n);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Make_Long (register long int n) {
|
2003-08-19 15:19:38 -04:00
|
|
|
if (n < 0 ? (n < (long)INT_MIN) : (n > (long)INT_MAX))
|
2003-09-02 04:12:11 -04:00
|
|
|
return Long_To_Bignum (n);
|
2003-08-19 15:19:38 -04:00
|
|
|
else
|
2003-09-02 04:12:11 -04:00
|
|
|
return Make_Integer ((int)n);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Make_Unsigned_Long (register unsigned long int n) {
|
|
|
|
if ((n & ~((unsigned long int)SIGNBIT-1)) == 0)
|
2003-09-02 04:12:11 -04:00
|
|
|
return Make_Integer ((int)n);
|
2003-08-19 15:19:38 -04:00
|
|
|
else
|
2003-09-02 04:12:11 -04:00
|
|
|
return Unsigned_Long_To_Bignum (n);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Fixnum_To_String (Object x, int radix) {
|
2003-08-19 15:19:38 -04:00
|
|
|
char buf[32];
|
|
|
|
register char *p;
|
2003-08-19 15:24:23 -04:00
|
|
|
register int n = FIXNUM(x), neg = 0;
|
2003-08-19 15:19:38 -04:00
|
|
|
|
|
|
|
if (n == 0)
|
2003-09-02 04:12:11 -04:00
|
|
|
return Make_String ("0", 1);
|
2003-08-19 15:19:38 -04:00
|
|
|
if (n < 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
neg++;
|
|
|
|
n = -n;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
p = buf+31;
|
|
|
|
*p = '\0';
|
|
|
|
while (n > 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
*--p = '0' + n % radix;
|
|
|
|
if (*p > '9')
|
|
|
|
*p = 'A' + (*p - '9') - 1;
|
|
|
|
n /= radix;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
if (neg)
|
2003-09-02 04:12:11 -04:00
|
|
|
*--p = '-';
|
2003-08-19 15:19:38 -04:00
|
|
|
return Make_String (p, strlen (p));
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
char *Flonum_To_String (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
static char buf[32];
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
sprintf (buf, "%.15g", FLONUM(x)->val);
|
|
|
|
for (p = buf; *p; p++)
|
2003-09-02 04:12:11 -04:00
|
|
|
if (*p == '.' || *p == 'e' || *p == 'N' || *p == 'i')
|
|
|
|
return buf;
|
2003-08-19 15:19:38 -04:00
|
|
|
*p++ = '.', *p++ = '0', *p++ = '\0';
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Number_To_String (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
int radix = 10;
|
|
|
|
Object x;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
x = argv[0];
|
|
|
|
if (argc == 2) {
|
2003-09-02 04:12:11 -04:00
|
|
|
radix = Get_Exact_Integer (argv[1]);
|
|
|
|
switch (radix) {
|
|
|
|
case 2: case 8: case 10: case 16:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Primitive_Error ("invalid radix: ~s", argv[1]);
|
|
|
|
}
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
Check_Number (x);
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Fixnum_To_String (x, radix);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_String (x, radix);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
if (radix != 10)
|
|
|
|
Primitive_Error ("radix for reals must be 10"); /* bleah! */
|
|
|
|
s = Flonum_To_String (x);
|
|
|
|
return Make_String (s, strlen (s));
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */
|
2003-09-02 04:12:11 -04:00
|
|
|
return Null;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
int Get_Integer (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
double d;
|
|
|
|
int expo;
|
|
|
|
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Integer (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
d = FLONUM(x)->val;
|
|
|
|
if (d != floor (d))
|
|
|
|
Wrong_Type (x, T_Fixnum);
|
|
|
|
(void)frexp (d, &expo);
|
|
|
|
if (expo <= 8 * (int)sizeof(int) - 1)
|
|
|
|
return d;
|
|
|
|
Primitive_Error ("integer out of range: ~s", x);
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
unsigned int Get_Unsigned (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
double d;
|
|
|
|
int expo;
|
|
|
|
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
if (FIXNUM(x) < 0)
|
|
|
|
goto err;
|
|
|
|
return FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Unsigned (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
d = FLONUM(x)->val;
|
|
|
|
if (d < 0)
|
|
|
|
goto err;
|
|
|
|
if (d != floor (d))
|
|
|
|
Wrong_Type (x, T_Fixnum);
|
|
|
|
(void)frexp (d, &expo);
|
|
|
|
if (expo <= 8 * (int)sizeof(int))
|
|
|
|
return d;
|
2003-08-19 15:19:38 -04:00
|
|
|
err:
|
2003-09-02 04:12:11 -04:00
|
|
|
Primitive_Error ("integer out of range: ~s", x);
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
long int Get_Long (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
double d;
|
|
|
|
int expo;
|
|
|
|
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Long (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
d = FLONUM(x)->val;
|
|
|
|
if (d != floor (d))
|
|
|
|
Wrong_Type (x, T_Fixnum);
|
|
|
|
(void)frexp (d, &expo);
|
|
|
|
if (expo <= 8 * (int)sizeof(long) - 1)
|
|
|
|
return d;
|
|
|
|
Primitive_Error ("integer out of range: ~s", x);
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
unsigned long int Get_Unsigned_Long (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
double d;
|
|
|
|
int expo;
|
|
|
|
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
if (FIXNUM(x) < 0)
|
|
|
|
goto err;
|
|
|
|
return (unsigned long int)FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Unsigned_Long (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
d = FLONUM(x)->val;
|
|
|
|
if (d < 0)
|
|
|
|
goto err;
|
|
|
|
if (d != floor (d))
|
|
|
|
Wrong_Type (x, T_Fixnum);
|
|
|
|
(void)frexp (d, &expo);
|
|
|
|
if (expo <= 8 * (int)sizeof(long))
|
|
|
|
return d;
|
2003-08-19 15:19:38 -04:00
|
|
|
err:
|
2003-09-02 04:12:11 -04:00
|
|
|
Primitive_Error ("integer out of range: ~s", x);
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
int Get_Exact_Integer (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Integer (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
unsigned int Get_Exact_Unsigned (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
if (FIXNUM(x) < 0)
|
|
|
|
Primitive_Error ("integer out of range: ~s", x);
|
|
|
|
return FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Unsigned (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
long int Get_Exact_Long (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Long (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
unsigned long int Get_Exact_Unsigned_Long (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
if (FIXNUM(x) < 0)
|
|
|
|
Primitive_Error ("integer out of range: ~s", x);
|
|
|
|
return FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Unsigned_Long (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
int Get_Index (Object n, Object obj) {
|
|
|
|
register int size, i;
|
2003-08-19 15:19:38 -04:00
|
|
|
|
|
|
|
i = Get_Exact_Integer (n);
|
|
|
|
size = TYPE(obj) == T_Vector ? VECTOR(obj)->size : STRING(obj)->size;
|
|
|
|
if (i < 0 || i >= size)
|
2003-09-02 04:12:11 -04:00
|
|
|
Range_Error (n);
|
2003-08-19 15:19:38 -04:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Make_Flonum (double d) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object num;
|
|
|
|
|
|
|
|
num = Alloc_Object (sizeof (struct S_Flonum), T_Flonum, 0);
|
|
|
|
FLONUM(num)->tag = Null;
|
|
|
|
FLONUM(num)->val = d;
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Make_Reduced_Flonum (double d) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object num;
|
|
|
|
int expo;
|
|
|
|
|
|
|
|
if (floor (d) == d) {
|
2003-09-02 04:12:11 -04:00
|
|
|
if (d == 0)
|
|
|
|
return Zero;
|
|
|
|
(void)frexp (d, &expo);
|
|
|
|
if (expo <= FIXBITS-1)
|
|
|
|
return Make_Integer ((int)d);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
num = Alloc_Object (sizeof (struct S_Flonum), T_Flonum, 0);
|
|
|
|
FLONUM(num)->tag = Null;
|
|
|
|
FLONUM(num)->val = d;
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
int Fixnum_Add (int a, int b, int *fits) {
|
2003-08-19 15:19:38 -04:00
|
|
|
int ret = a + b;
|
|
|
|
|
|
|
|
*fits = 1;
|
|
|
|
if (a > 0 && b > 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
if (ret < 0) *fits = 0;
|
2003-08-19 15:19:38 -04:00
|
|
|
} else if (a < 0 && b < 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
if (ret > 0) *fits = 0;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
int Fixnum_Sub (int a, int b, int *fits) {
|
2003-08-19 15:19:38 -04:00
|
|
|
int ret = a - b;
|
|
|
|
|
|
|
|
*fits = 1;
|
|
|
|
if (a < 0 && b > 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
if (ret > 0) *fits = 0;
|
2003-08-19 15:19:38 -04:00
|
|
|
} else if (a > 0 && b < 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
if (ret < 0) *fits = 0;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function assumes 32bit integers. This doesn't really matter,
|
|
|
|
* because if the `*' primitive resorts to bignum multiplication, the
|
|
|
|
* resulting bignum gets reduced to a fixnum (if it fits) anyway.
|
|
|
|
* (This should be fixed, though...)
|
|
|
|
*/
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Fixnum_Multiply (int a, int b) {
|
|
|
|
register unsigned int aa = a;
|
|
|
|
register unsigned int ab = b;
|
|
|
|
register unsigned int prod, prod2;
|
|
|
|
register int sign = 1;
|
2003-08-19 15:19:38 -04:00
|
|
|
if (a < 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
aa = -a;
|
|
|
|
sign = -1;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
if (b < 0) {
|
2003-09-02 04:12:11 -04:00
|
|
|
ab = -b;
|
|
|
|
sign = -sign;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
prod = (aa & 0xFFFF) * (ab & 0xFFFF);
|
|
|
|
if (aa & 0xFFFF0000) {
|
2003-09-02 04:12:11 -04:00
|
|
|
if (ab & 0xFFFF0000)
|
|
|
|
return Null;
|
|
|
|
prod2 = (aa >> 16) * ab;
|
2003-08-19 15:19:38 -04:00
|
|
|
} else {
|
2003-09-02 04:12:11 -04:00
|
|
|
prod2 = aa * (ab >> 16);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
prod2 += prod >> 16;
|
|
|
|
prod &= 0xFFFF;
|
|
|
|
if (prod2 > (1 << (FIXBITS - 1 - 16)) - 1) {
|
2003-09-02 04:12:11 -04:00
|
|
|
if (sign == 1 || prod2 != (1 << (FIXBITS - 1 - 16)) || prod != 0)
|
|
|
|
return Null;
|
|
|
|
return Make_Integer (-(unsigned int)SIGNBIT);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
prod += prod2 << 16;
|
|
|
|
if (sign == -1)
|
2003-09-02 04:12:11 -04:00
|
|
|
prod = - prod;
|
2003-08-19 15:19:38 -04:00
|
|
|
return Make_Integer (prod);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Integerp (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
double d;
|
|
|
|
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum: case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return True;
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
d = FLONUM(x)->val;
|
|
|
|
return d == floor(d) ? True : False;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
return False;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Rationalp (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return P_Integerp (x);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Realp (Object x) {
|
|
|
|
register int t = TYPE(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
return t == T_Flonum || t == T_Fixnum || t == T_Bignum ? True : False;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Complexp (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return P_Realp (x);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Numberp (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return P_Complexp (x);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Exactp (Object n) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Check_Number (n);
|
|
|
|
return TYPE(n) == T_Flonum ? False : True;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Inexactp (Object n) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Check_Number (n);
|
|
|
|
return TYPE(n) == T_Flonum ? True : False;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Exact_To_Inexact (Object n) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Check_Number (n);
|
|
|
|
switch (TYPE(n)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Make_Flonum ((double)FIXNUM(n));
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return n;
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Make_Flonum (Bignum_To_Double (n));
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */
|
2003-09-02 04:12:11 -04:00
|
|
|
return Null;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Inexact_To_Exact (Object n) {
|
2003-08-19 15:19:38 -04:00
|
|
|
double d;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
Check_Number (n);
|
|
|
|
switch (TYPE(n)) {
|
|
|
|
case T_Fixnum:
|
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return n;
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
d = floor (FLONUM(n)->val + 0.5);
|
|
|
|
(void)frexp (d, &i);
|
|
|
|
return (i <= FIXBITS-1) ? Make_Integer ((int)d) : Double_To_Bignum (d);
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */
|
2003-09-02 04:12:11 -04:00
|
|
|
return Null;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
#define General_Generic_Predicate(prim,op,bigop) Object prim (Object x) {\
|
|
|
|
register int ret;\
|
2003-08-19 15:19:38 -04:00
|
|
|
Check_Number (x);\
|
|
|
|
switch (TYPE(x)) {\
|
|
|
|
case T_Flonum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = FLONUM(x)->val op 0; break;\
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Fixnum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = FIXNUM(x) op 0; break;\
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = bigop (x); break;\
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */\
|
2003-09-02 04:12:11 -04:00
|
|
|
return False;\
|
2003-08-19 15:19:38 -04:00
|
|
|
}\
|
|
|
|
return ret ? True : False;\
|
|
|
|
}
|
|
|
|
|
|
|
|
General_Generic_Predicate (P_Zerop, ==, Bignum_Zero)
|
|
|
|
General_Generic_Predicate (P_Negativep, <, Bignum_Negative)
|
|
|
|
General_Generic_Predicate (P_Positivep, >, Bignum_Positive)
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Evenp (Object x) {
|
|
|
|
register int ret;
|
2003-08-19 15:19:38 -04:00
|
|
|
double d;
|
|
|
|
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = !(FIXNUM(x) & 1); break;
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = Bignum_Even (x); break;
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
d = FLONUM(x)->val;
|
|
|
|
if (floor (d) == d) {
|
|
|
|
d /= 2;
|
|
|
|
ret = floor (d) == d;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*FALLTHROUGH*/
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
|
|
|
/*NOTREACHED*/
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
return ret ? True : False;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Oddp (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object tmp;
|
|
|
|
tmp = P_Evenp (x);
|
|
|
|
return EQ(tmp,True) ? False : True;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
#define General_Generic_Compare(name,op,bigop) int name (Object x, Object y) {\
|
|
|
|
Object b; register int ret;\
|
2003-08-19 15:19:38 -04:00
|
|
|
GC_Node;\
|
|
|
|
\
|
|
|
|
switch (TYPE(x)) {\
|
|
|
|
case T_Fixnum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {\
|
|
|
|
case T_Fixnum:\
|
|
|
|
return FIXNUM(x) op FIXNUM(y);\
|
|
|
|
case T_Flonum:\
|
|
|
|
return FIXNUM(x) op FLONUM(y)->val;\
|
|
|
|
case T_Bignum:\
|
|
|
|
GC_Link (y);\
|
|
|
|
b = Integer_To_Bignum (FIXNUM(x));\
|
|
|
|
ret = bigop (b, y);\
|
|
|
|
GC_Unlink;\
|
|
|
|
return ret;\
|
|
|
|
default: /* Just to avoid compiler warnings */\
|
|
|
|
return 0;\
|
|
|
|
}\
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {\
|
|
|
|
case T_Fixnum:\
|
|
|
|
return FLONUM(x)->val op FIXNUM(y);\
|
|
|
|
case T_Flonum:\
|
|
|
|
return FLONUM(x)->val op FLONUM(y)->val;\
|
|
|
|
case T_Bignum:\
|
|
|
|
return FLONUM(x)->val op Bignum_To_Double (y);\
|
|
|
|
default: /* Just to avoid compiler warnings */\
|
|
|
|
return 0;\
|
|
|
|
}\
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {\
|
|
|
|
case T_Fixnum:\
|
|
|
|
GC_Link (x);\
|
|
|
|
b = Integer_To_Bignum (FIXNUM(y));\
|
|
|
|
ret = bigop (x, b);\
|
|
|
|
GC_Unlink;\
|
|
|
|
return ret;\
|
|
|
|
case T_Flonum:\
|
|
|
|
return Bignum_To_Double (x) op FLONUM(y)->val;\
|
|
|
|
case T_Bignum:\
|
|
|
|
return bigop (x, y);\
|
|
|
|
default: /* Just to avoid compiler warnings */\
|
|
|
|
return 0;\
|
|
|
|
}\
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */\
|
2003-09-02 04:12:11 -04:00
|
|
|
return 0;\
|
2003-08-19 15:19:38 -04:00
|
|
|
}\
|
|
|
|
/*NOTREACHED*/ /* ...but lint never sees it */\
|
|
|
|
}
|
|
|
|
|
|
|
|
General_Generic_Compare (Generic_Equal, ==, Bignum_Equal)
|
|
|
|
General_Generic_Compare (Generic_Less, <, Bignum_Less)
|
|
|
|
General_Generic_Compare (Generic_Greater, >, Bignum_Greater)
|
|
|
|
General_Generic_Compare (Generic_Eq_Less, <=, Bignum_Eq_Less)
|
|
|
|
General_Generic_Compare (Generic_Eq_Greater, >=, Bignum_Eq_Greater)
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object General_Compare (int argc, Object *argv, register int (*op)()) {
|
|
|
|
register int i;
|
2003-08-19 15:19:38 -04:00
|
|
|
|
|
|
|
Check_Number (argv[0]);
|
|
|
|
for (i = 1; i < argc; i++) {
|
2003-09-02 04:12:11 -04:00
|
|
|
Check_Number (argv[i]);
|
|
|
|
if (!(*op) (argv[i-1], argv[i]))
|
|
|
|
return False;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
return True;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Equal (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Compare (argc, argv, Generic_Equal);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Less (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Compare (argc, argv, Generic_Less);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Greater (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Compare (argc, argv, Generic_Greater);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Eq_Less (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Compare (argc, argv, Generic_Eq_Less);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Eq_Greater (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Compare (argc, argv, Generic_Eq_Greater);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
#define General_Generic_Operator(name,op,fixop,bigop) Object name (Object x,\
|
2003-09-02 04:12:11 -04:00
|
|
|
Object y) {\
|
2003-08-19 15:24:23 -04:00
|
|
|
Object b1, b2, ret; register int i;\
|
2003-08-19 15:19:38 -04:00
|
|
|
int fits;\
|
|
|
|
GC_Node2;\
|
|
|
|
\
|
|
|
|
switch (TYPE(x)) {\
|
|
|
|
case T_Fixnum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {\
|
|
|
|
case T_Fixnum:\
|
|
|
|
i = fixop (FIXNUM(x), FIXNUM(y), &fits);\
|
|
|
|
if (fits)\
|
|
|
|
return Make_Integer (i);\
|
|
|
|
b1 = b2 = Null;\
|
|
|
|
GC_Link2 (b1, b2);\
|
|
|
|
b1 = Integer_To_Bignum (FIXNUM(x));\
|
|
|
|
b2 = Integer_To_Bignum (FIXNUM(y));\
|
|
|
|
ret = bigop (b1, b2);\
|
|
|
|
GC_Unlink;\
|
|
|
|
return ret;\
|
|
|
|
case T_Flonum:\
|
|
|
|
return Make_Flonum (FIXNUM(x) op FLONUM(y)->val);\
|
|
|
|
case T_Bignum:\
|
|
|
|
GC_Link (y);\
|
|
|
|
b1 = Integer_To_Bignum (FIXNUM(x));\
|
|
|
|
ret = bigop (b1, y);\
|
|
|
|
GC_Unlink;\
|
|
|
|
return ret;\
|
|
|
|
default: /* Just to avoid compiler warnings */\
|
|
|
|
return False;\
|
|
|
|
}\
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {\
|
|
|
|
case T_Fixnum:\
|
|
|
|
return Make_Flonum (FLONUM(x)->val op FIXNUM(y));\
|
|
|
|
case T_Flonum:\
|
|
|
|
return Make_Flonum (FLONUM(x)->val op FLONUM(y)->val);\
|
|
|
|
case T_Bignum:\
|
|
|
|
return Make_Flonum (FLONUM(x)->val op Bignum_To_Double (y));\
|
|
|
|
default: /* Just to avoid compiler warnings */\
|
|
|
|
return False;\
|
|
|
|
}\
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:\
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {\
|
|
|
|
case T_Fixnum:\
|
|
|
|
GC_Link (x);\
|
|
|
|
b1 = Integer_To_Bignum (FIXNUM(y));\
|
|
|
|
ret = bigop (x, b1);\
|
|
|
|
GC_Unlink;\
|
|
|
|
return ret;\
|
|
|
|
case T_Flonum:\
|
|
|
|
return Make_Flonum (Bignum_To_Double (x) op FLONUM(y)->val);\
|
|
|
|
case T_Bignum:\
|
|
|
|
return bigop (x, y);\
|
|
|
|
default: /* Just to avoid compiler warnings */\
|
|
|
|
return False;\
|
|
|
|
}\
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */\
|
2003-09-02 04:12:11 -04:00
|
|
|
return False;\
|
2003-08-19 15:19:38 -04:00
|
|
|
}\
|
|
|
|
/*NOTREACHED*/ /* ...but lint never sees it */\
|
|
|
|
}
|
|
|
|
|
|
|
|
General_Generic_Operator (Generic_Plus, +, Fixnum_Add, Bignum_Plus)
|
|
|
|
General_Generic_Operator (Generic_Minus, -, Fixnum_Sub, Bignum_Minus)
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Inc (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Check_Number (x);
|
|
|
|
return Generic_Plus (x, One);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Dec (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Check_Number (x);
|
|
|
|
return Generic_Minus (x, One);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object General_Operator (int argc, Object *argv, Object start,
|
2003-09-02 04:12:11 -04:00
|
|
|
register Object (*op)()) {
|
2003-08-19 15:24:23 -04:00
|
|
|
register int i;
|
2003-08-19 15:19:38 -04:00
|
|
|
Object accum;
|
|
|
|
|
|
|
|
if (argc > 0)
|
2003-09-02 04:12:11 -04:00
|
|
|
Check_Number (argv[0]);
|
2003-08-19 15:19:38 -04:00
|
|
|
accum = start;
|
|
|
|
switch (argc) {
|
|
|
|
case 0:
|
2003-09-02 04:12:11 -04:00
|
|
|
break;
|
2003-08-19 15:19:38 -04:00
|
|
|
case 1:
|
2003-09-02 04:12:11 -04:00
|
|
|
accum = (*op) (accum, argv[0]); break;
|
2003-08-19 15:19:38 -04:00
|
|
|
default:
|
2003-09-02 04:12:11 -04:00
|
|
|
for (accum = argv[0], i = 1; i < argc; i++) {
|
|
|
|
Check_Number (argv[i]);
|
|
|
|
accum = (*op) (accum, argv[i]);
|
|
|
|
}
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
return accum;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Plus (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Operator (argc, argv, Zero, Generic_Plus);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Minus (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Operator (argc, argv, Zero, Generic_Minus);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Multiply (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Operator (argc, argv, One, Generic_Multiply);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Generic_Divide (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Operator (argc, argv, One, Generic_Divide);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Generic_Multiply (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object b, ret;
|
|
|
|
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {
|
|
|
|
case T_Fixnum:
|
|
|
|
ret = Fixnum_Multiply (FIXNUM(x), FIXNUM(y));
|
|
|
|
if (Nullp (ret)) {
|
|
|
|
b = Integer_To_Bignum (FIXNUM(x));
|
|
|
|
return Bignum_Fixnum_Multiply (b, y);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
case T_Flonum:
|
|
|
|
return Make_Flonum (FIXNUM(x) * FLONUM(y)->val);
|
|
|
|
case T_Bignum:
|
|
|
|
return Bignum_Fixnum_Multiply (y, x);
|
|
|
|
default: /* Just to avoid compiler warnings */
|
|
|
|
return Null;
|
|
|
|
}
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {
|
|
|
|
case T_Fixnum:
|
|
|
|
return Make_Flonum (FLONUM(x)->val * FIXNUM(y));
|
|
|
|
case T_Flonum:
|
|
|
|
return Make_Flonum (FLONUM(x)->val * FLONUM(y)->val);
|
|
|
|
case T_Bignum:
|
|
|
|
return Make_Flonum (FLONUM(x)->val * Bignum_To_Double (y));
|
|
|
|
default: /* Just to avoid compiler warnings */
|
|
|
|
return Null;
|
|
|
|
}
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {
|
|
|
|
case T_Fixnum:
|
|
|
|
return Bignum_Fixnum_Multiply (x, y);
|
|
|
|
case T_Flonum:
|
|
|
|
return Make_Flonum (Bignum_To_Double (x) * FLONUM(y)->val);
|
|
|
|
case T_Bignum:
|
|
|
|
return Bignum_Multiply (x, y);
|
|
|
|
default: /* Just to avoid compiler warnings */
|
|
|
|
return Null;
|
|
|
|
}
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */
|
2003-09-02 04:12:11 -04:00
|
|
|
return Null;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Generic_Divide (Object x, Object y) {
|
|
|
|
register int t = TYPE(y);
|
2003-08-19 15:19:38 -04:00
|
|
|
Object b, ret;
|
|
|
|
GC_Node2;
|
|
|
|
|
|
|
|
if (t == T_Fixnum ? FIXNUM(y) == 0 :
|
2003-09-02 04:12:11 -04:00
|
|
|
(t == T_Flonum ? FLONUM(y) == 0 : Bignum_Zero (y)))
|
|
|
|
Range_Error (y);
|
2003-08-19 15:19:38 -04:00
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (t) {
|
|
|
|
case T_Fixnum:
|
|
|
|
return Make_Reduced_Flonum ((double)FIXNUM(x) / (double)FIXNUM(y));
|
|
|
|
case T_Flonum:
|
|
|
|
return Make_Flonum ((double)FIXNUM(x) / FLONUM(y)->val);
|
|
|
|
case T_Bignum:
|
|
|
|
GC_Link (y);
|
|
|
|
b = Integer_To_Bignum (FIXNUM(x));
|
|
|
|
ret = Bignum_Divide (b, y);
|
|
|
|
GC_Unlink;
|
|
|
|
if (EQ(Cdr (ret),Zero))
|
|
|
|
return Car (ret);
|
|
|
|
return Make_Reduced_Flonum ((double)FIXNUM(x)
|
|
|
|
/ Bignum_To_Double (y));
|
|
|
|
default: /* Just to avoid compiler warnings */
|
|
|
|
return Null;
|
|
|
|
}
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (t) {
|
|
|
|
case T_Fixnum:
|
|
|
|
return Make_Flonum (FLONUM(x)->val / (double)FIXNUM(y));
|
|
|
|
case T_Flonum:
|
|
|
|
return Make_Flonum (FLONUM(x)->val / FLONUM(y)->val);
|
|
|
|
case T_Bignum:
|
|
|
|
return Make_Flonum (FLONUM(x)->val / Bignum_To_Double (y));
|
|
|
|
default: /* Just to avoid compiler warnings */
|
|
|
|
return Null;
|
|
|
|
}
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (t) {
|
|
|
|
case T_Fixnum:
|
|
|
|
GC_Link (x);
|
|
|
|
ret = Bignum_Fixnum_Divide (x, y);
|
|
|
|
GC_Unlink;
|
|
|
|
if (EQ(Cdr (ret),Zero))
|
|
|
|
return Car (ret);
|
|
|
|
return Make_Reduced_Flonum (Bignum_To_Double (x)
|
|
|
|
/ (double)FIXNUM(y));
|
|
|
|
case T_Flonum:
|
|
|
|
return Make_Flonum (Bignum_To_Double (x) / FLONUM(y)->val);
|
|
|
|
case T_Bignum:
|
|
|
|
GC_Link2 (x, y);
|
|
|
|
ret = Bignum_Divide (x, y);
|
|
|
|
GC_Unlink;
|
|
|
|
if (EQ(Cdr (ret),Zero))
|
|
|
|
return Car (ret);
|
|
|
|
return Make_Reduced_Flonum (Bignum_To_Double (x)
|
|
|
|
/ Bignum_To_Double (y));
|
|
|
|
default: /* Just to avoid compiler warnings */
|
|
|
|
return Null;
|
|
|
|
}
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */
|
2003-09-02 04:12:11 -04:00
|
|
|
return Null;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Abs (Object x) {
|
|
|
|
register int i;
|
2003-08-19 15:19:38 -04:00
|
|
|
|
|
|
|
Check_Number (x);
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
i = FIXNUM(x);
|
|
|
|
return i < 0 ? Make_Integer (-i) : x;
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Make_Flonum (fabs (FLONUM(x)->val));
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_Abs (x);
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */
|
2003-09-02 04:12:11 -04:00
|
|
|
return Null;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object General_Integer_Divide (Object x, Object y, int rem) {
|
|
|
|
register int fx = FIXNUM(x), fy = FIXNUM(y);
|
2003-08-19 15:19:38 -04:00
|
|
|
Object b, ret;
|
|
|
|
GC_Node;
|
|
|
|
|
|
|
|
if (TYPE(y) == T_Fixnum ? FIXNUM(y) == 0 : Bignum_Zero (y))
|
2003-09-02 04:12:11 -04:00
|
|
|
Range_Error (y);
|
2003-08-19 15:19:38 -04:00
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {
|
|
|
|
case T_Fixnum:
|
|
|
|
return Make_Integer (rem ? (fx % fy) : (fx / fy));
|
|
|
|
case T_Bignum:
|
|
|
|
GC_Link (y);
|
|
|
|
b = Integer_To_Bignum (fx);
|
|
|
|
GC_Unlink;
|
|
|
|
ret = Bignum_Divide (b, y);
|
2003-08-19 15:19:38 -04:00
|
|
|
done:
|
2003-09-02 04:12:11 -04:00
|
|
|
return rem ? Cdr (ret) : Car (ret);
|
|
|
|
default: /* Just to avoid compiler warnings */
|
|
|
|
return Null;
|
|
|
|
}
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
switch (TYPE(y)) {
|
|
|
|
case T_Fixnum:
|
|
|
|
ret = Bignum_Fixnum_Divide (x, y);
|
|
|
|
goto done;
|
|
|
|
case T_Bignum:
|
|
|
|
ret = Bignum_Divide (x, y);
|
|
|
|
goto done;
|
|
|
|
default: /* Just to avoid compiler warnings */
|
|
|
|
return Null;
|
|
|
|
}
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */
|
2003-09-02 04:12:11 -04:00
|
|
|
return Null;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Exact_Quotient (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Integer_Divide (x, y, 0);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Exact_Remainder (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Integer_Divide (x, y, 1);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Exact_Modulo (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object rem, xneg, yneg;
|
|
|
|
GC_Node2;
|
|
|
|
|
|
|
|
GC_Link2 (x, y);
|
|
|
|
rem = General_Integer_Divide (x, y, 1);
|
2003-08-19 15:27:51 -04:00
|
|
|
if (!EQ(rem,Zero)) {
|
2003-09-02 04:12:11 -04:00
|
|
|
xneg = P_Negativep (x);
|
|
|
|
yneg = P_Negativep (y);
|
|
|
|
if (!EQ(xneg,yneg))
|
|
|
|
rem = Generic_Plus (rem, y);
|
2003-08-19 15:27:51 -04:00
|
|
|
}
|
2003-08-19 15:19:38 -04:00
|
|
|
GC_Unlink;
|
|
|
|
return rem;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object With_Exact_Ints (Object x, Object y, Object (*fun)()) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object i, ret;
|
|
|
|
int inex = 0;
|
|
|
|
GC_Node3;
|
|
|
|
|
|
|
|
ret = Null;
|
|
|
|
GC_Link3 (x, y, ret);
|
|
|
|
i = P_Integerp (x);
|
|
|
|
if (!EQ(i,True))
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (x, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
i = P_Integerp (y);
|
|
|
|
if (!EQ(i,True))
|
2003-09-02 04:12:11 -04:00
|
|
|
Wrong_Type (y, T_Fixnum);
|
2003-08-19 15:19:38 -04:00
|
|
|
if (TYPE(x) == T_Flonum) {
|
2003-09-02 04:12:11 -04:00
|
|
|
x = P_Inexact_To_Exact (x); inex++;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
if (TYPE(y) == T_Flonum) {
|
2003-09-02 04:12:11 -04:00
|
|
|
y = P_Inexact_To_Exact (y); inex++;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
ret = fun (x, y);
|
|
|
|
if (inex)
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = P_Exact_To_Inexact (ret);
|
2003-08-19 15:19:38 -04:00
|
|
|
GC_Unlink;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Quotient (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return With_Exact_Ints (x, y, Exact_Quotient);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Remainder (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return With_Exact_Ints (x, y, Exact_Remainder);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Modulo (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return With_Exact_Ints (x, y, Exact_Modulo);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Exact_Gcd (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object r, z;
|
|
|
|
GC_Node2;
|
|
|
|
|
|
|
|
GC_Link2 (x, y);
|
|
|
|
while (1) {
|
2003-09-02 04:12:11 -04:00
|
|
|
z = P_Zerop (x);
|
|
|
|
if (EQ(z,True)) {
|
|
|
|
r = y;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
z = P_Zerop (y);
|
|
|
|
if (EQ(z,True)) {
|
|
|
|
r = x;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
r = General_Integer_Divide (x, y, 1);
|
|
|
|
x = y;
|
|
|
|
y = r;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
GC_Unlink;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object General_Gcd (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return With_Exact_Ints (x, y, Exact_Gcd);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Gcd (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return P_Abs (General_Operator (argc, argv, Zero, General_Gcd));
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Exact_Lcm (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object ret, p, z;
|
|
|
|
GC_Node3;
|
|
|
|
|
|
|
|
ret = Null;
|
|
|
|
GC_Link3 (x, y, ret);
|
|
|
|
ret = Exact_Gcd (x, y);
|
|
|
|
z = P_Zerop (ret);
|
|
|
|
if (!EQ(z,True)) {
|
2003-09-02 04:12:11 -04:00
|
|
|
p = Generic_Multiply (x, y);
|
|
|
|
ret = General_Integer_Divide (p, ret, 0);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
GC_Unlink;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object General_Lcm (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return With_Exact_Ints (x, y, Exact_Lcm);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Lcm (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return P_Abs (General_Operator (argc, argv, One, General_Lcm));
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
#define General_Conversion(name,op) Object name (Object x) {\
|
2003-08-19 15:19:38 -04:00
|
|
|
double d, i;\
|
|
|
|
\
|
|
|
|
Check_Number (x);\
|
|
|
|
if (TYPE(x) != T_Flonum)\
|
2003-09-02 04:12:11 -04:00
|
|
|
return x;\
|
2003-08-19 15:19:38 -04:00
|
|
|
d = FLONUM(x)->val;\
|
|
|
|
(void)modf (op (d), &i);\
|
|
|
|
return Make_Flonum (i);\
|
|
|
|
}
|
|
|
|
|
|
|
|
#define trunc(x) (x)
|
|
|
|
|
|
|
|
General_Conversion (P_Floor, floor)
|
|
|
|
General_Conversion (P_Ceiling, ceil)
|
|
|
|
General_Conversion (P_Truncate, trunc)
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Round (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
double d, y, f;
|
|
|
|
Object ret, isodd;
|
|
|
|
|
|
|
|
Check_Number (x);
|
|
|
|
if (TYPE(x) != T_Flonum)
|
2003-09-02 04:12:11 -04:00
|
|
|
return x;
|
2003-08-19 15:19:38 -04:00
|
|
|
d = FLONUM(x)->val;
|
|
|
|
y = d + 0.5;
|
|
|
|
f = floor (y);
|
|
|
|
ret = Make_Flonum (f);
|
|
|
|
if (y == f) {
|
2003-09-02 04:12:11 -04:00
|
|
|
isodd = P_Oddp (ret);
|
|
|
|
if (Truep (isodd))
|
|
|
|
FLONUM(ret)->val--;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
double Get_Double (Object x) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Check_Number (x);
|
|
|
|
switch (TYPE(x)) {
|
|
|
|
case T_Fixnum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return (double)FIXNUM(x);
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Flonum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return FLONUM(x)->val;
|
2003-08-19 15:19:38 -04:00
|
|
|
case T_Bignum:
|
2003-09-02 04:12:11 -04:00
|
|
|
return Bignum_To_Double (x);
|
2003-08-19 15:24:23 -04:00
|
|
|
default: /* Just to avoid compiler warnings */
|
2003-09-02 04:12:11 -04:00
|
|
|
return 0.0;
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object General_Function (Object x, Object y, double (*fun)()) {
|
2003-08-19 15:19:38 -04:00
|
|
|
double d, ret;
|
|
|
|
|
|
|
|
d = Get_Double (x);
|
|
|
|
errno = 0;
|
|
|
|
if (Nullp (y))
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = (*fun) (d);
|
2003-08-19 15:19:38 -04:00
|
|
|
else
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = (*fun) (d, Get_Double (y));
|
2003-08-19 15:19:38 -04:00
|
|
|
if (errno == ERANGE || errno == EDOM)
|
2003-09-02 04:12:11 -04:00
|
|
|
Range_Error (x);
|
2003-08-19 15:19:38 -04:00
|
|
|
return Make_Flonum (ret);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Sqrt (Object x) { return General_Function (x, Null, sqrt); }
|
2003-08-19 15:19:38 -04:00
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Exp (Object x) { return General_Function (x, Null, exp); }
|
2003-08-19 15:19:38 -04:00
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Log (Object x) { return General_Function (x, Null, log); }
|
2003-08-19 15:19:38 -04:00
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Sin (Object x) { return General_Function (x, Null, sin); }
|
2003-08-19 15:19:38 -04:00
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Cos (Object x) { return General_Function (x, Null, cos); }
|
2003-08-19 15:19:38 -04:00
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Tan (Object x) { return General_Function (x, Null, tan); }
|
2003-08-19 15:19:38 -04:00
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Asin (Object x) { return General_Function (x, Null, asin); }
|
2003-08-19 15:19:38 -04:00
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Acos (Object x) { return General_Function (x, Null, acos); }
|
2003-08-19 15:19:38 -04:00
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Atan (int argc, Object *argv) {
|
|
|
|
register int a2 = argc == 2;
|
|
|
|
return General_Function (argv[0], a2 ? argv[1] : Null, a2 ?
|
2003-09-02 04:12:11 -04:00
|
|
|
(double(*)())atan2 : (double(*)())atan);
|
2003-08-19 15:19:38 -04:00
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Min (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object ret;
|
2003-08-19 15:24:23 -04:00
|
|
|
|
2003-08-19 15:19:38 -04:00
|
|
|
ret = Generic_Less (x, y) ? x : y;
|
|
|
|
if (TYPE(x) == T_Flonum || TYPE(y) == T_Flonum)
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = P_Exact_To_Inexact (ret);
|
2003-08-19 15:19:38 -04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object Max (Object x, Object y) {
|
2003-08-19 15:19:38 -04:00
|
|
|
Object ret;
|
2003-08-19 15:24:23 -04:00
|
|
|
|
2003-08-19 15:19:38 -04:00
|
|
|
ret = Generic_Less (x, y) ? y : x;
|
|
|
|
if (TYPE(x) == T_Flonum || TYPE(y) == T_Flonum)
|
2003-09-02 04:12:11 -04:00
|
|
|
ret = P_Exact_To_Inexact (ret);
|
2003-08-19 15:19:38 -04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Min (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Operator (argc, argv, argv[0], Min);
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Max (int argc, Object *argv) {
|
2003-08-19 15:19:38 -04:00
|
|
|
return General_Operator (argc, argv, argv[0], Max);
|
|
|
|
}
|
|
|
|
|
|
|
|
Object P_Random () {
|
2003-08-25 10:17:09 -04:00
|
|
|
#ifdef HAVE_RANDOM
|
2003-08-19 15:24:23 -04:00
|
|
|
extern long int random();
|
2003-08-19 15:19:38 -04:00
|
|
|
return Make_Long (random ());
|
|
|
|
#else
|
|
|
|
return Make_Integer (rand ());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-08-19 15:24:23 -04:00
|
|
|
Object P_Srandom (Object x) {
|
2003-08-25 10:17:09 -04:00
|
|
|
#ifdef HAVE_RANDOM
|
2003-08-19 15:19:38 -04:00
|
|
|
srandom (Get_Unsigned (x));
|
|
|
|
#else
|
|
|
|
srand (Get_Unsigned (x));
|
|
|
|
#endif
|
|
|
|
return x;
|
|
|
|
}
|