1478 lines
26 KiB
C
1478 lines
26 KiB
C
/*
|
|
* Copyright (c) 2001 by The XFree86 Project, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of the XFree86 Project shall
|
|
* not be used in advertising or otherwise to promote the sale, use or other
|
|
* dealings in this Software without prior written authorization from the
|
|
* XFree86 Project.
|
|
*
|
|
* Author: Paulo César Pereira de Andrade
|
|
*/
|
|
|
|
/* $XFree86: xc/programs/xedit/lisp/math.c,v 1.23tsi Exp $ */
|
|
|
|
#include "lisp/math.h"
|
|
#include "lisp/private.h"
|
|
|
|
#ifdef __UNIXOS2__
|
|
# define finite(x) isfinite(x)
|
|
#endif
|
|
|
|
/*
|
|
* Prototypes
|
|
*/
|
|
static LispObj *LispDivide(LispBuiltin*, int, int);
|
|
|
|
/*
|
|
* Initialization
|
|
*/
|
|
static LispObj *obj_zero, *obj_one;
|
|
LispObj *Ocomplex, *Oequal_;
|
|
|
|
LispObj *Oshort_float, *Osingle_float, *Odouble_float, *Olong_float;
|
|
|
|
Atom_id Sdefault_float_format;
|
|
|
|
/*
|
|
* Implementation
|
|
*/
|
|
#include "lisp/mathimp.c"
|
|
|
|
void
|
|
LispMathInit(void)
|
|
{
|
|
LispObj *object, *result;
|
|
|
|
mp_set_malloc(LispMalloc);
|
|
mp_set_calloc(LispCalloc);
|
|
mp_set_realloc(LispRealloc);
|
|
mp_set_free(LispFree);
|
|
|
|
number_init();
|
|
obj_zero = FIXNUM(0);
|
|
obj_one = FIXNUM(1);
|
|
|
|
Oequal_ = STATIC_ATOM("=");
|
|
Ocomplex = STATIC_ATOM(Scomplex);
|
|
Oshort_float = STATIC_ATOM("SHORT-FLOAT");
|
|
LispExportSymbol(Oshort_float);
|
|
Osingle_float = STATIC_ATOM("SINGLE-FLOAT");
|
|
LispExportSymbol(Osingle_float);
|
|
Odouble_float = STATIC_ATOM("DOUBLE-FLOAT");
|
|
LispExportSymbol(Odouble_float);
|
|
Olong_float = STATIC_ATOM("LONG-FLOAT");
|
|
LispExportSymbol(Olong_float);
|
|
|
|
object = STATIC_ATOM("*DEFAULT-FLOAT-FORMAT*");
|
|
LispProclaimSpecial(object, Odouble_float, NIL);
|
|
LispExportSymbol(object);
|
|
Sdefault_float_format = ATOMID(object);
|
|
|
|
object = STATIC_ATOM("PI");
|
|
result = number_pi();
|
|
LispProclaimSpecial(object, result, NIL);
|
|
LispExportSymbol(object);
|
|
|
|
object = STATIC_ATOM("MOST-POSITIVE-FIXNUM");
|
|
LispDefconstant(object, FIXNUM(MOST_POSITIVE_FIXNUM), NIL);
|
|
LispExportSymbol(object);
|
|
|
|
object = STATIC_ATOM("MOST-NEGATIVE-FIXNUM");
|
|
LispDefconstant(object, FIXNUM(MOST_NEGATIVE_FIXNUM), NIL);
|
|
LispExportSymbol(object);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Mul(LispBuiltin *builtin)
|
|
/*
|
|
* &rest numbers
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *number, *numbers;
|
|
|
|
numbers = ARGUMENT(0);
|
|
|
|
if (CONSP(numbers)) {
|
|
number = CAR(numbers);
|
|
|
|
numbers = CDR(numbers);
|
|
if (!CONSP(numbers)) {
|
|
CHECK_NUMBER(number);
|
|
return (number);
|
|
}
|
|
}
|
|
else
|
|
return (FIXNUM(1));
|
|
|
|
set_number_object(&num, number);
|
|
do {
|
|
mul_number_object(&num, CAR(numbers));
|
|
numbers = CDR(numbers);
|
|
} while (CONSP(numbers));
|
|
|
|
return (make_number_object(&num));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Plus(LispBuiltin *builtin)
|
|
/*
|
|
+ &rest numbers
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *number, *numbers;
|
|
|
|
numbers = ARGUMENT(0);
|
|
|
|
if (CONSP(numbers)) {
|
|
number = CAR(numbers);
|
|
|
|
numbers = CDR(numbers);
|
|
if (!CONSP(numbers)) {
|
|
CHECK_NUMBER(number);
|
|
return (number);
|
|
}
|
|
}
|
|
else
|
|
return (FIXNUM(0));
|
|
|
|
set_number_object(&num, number);
|
|
do {
|
|
add_number_object(&num, CAR(numbers));
|
|
numbers = CDR(numbers);
|
|
} while (CONSP(numbers));
|
|
|
|
return (make_number_object(&num));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Minus(LispBuiltin *builtin)
|
|
/*
|
|
- number &rest more_numbers
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
number = ARGUMENT(0);
|
|
|
|
set_number_object(&num, number);
|
|
if (!CONSP(more_numbers)) {
|
|
neg_number(&num);
|
|
|
|
return (make_number_object(&num));
|
|
}
|
|
do {
|
|
sub_number_object(&num, CAR(more_numbers));
|
|
more_numbers = CDR(more_numbers);
|
|
} while (CONSP(more_numbers));
|
|
|
|
return (make_number_object(&num));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Div(LispBuiltin *builtin)
|
|
/*
|
|
/ number &rest more_numbers
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
number = ARGUMENT(0);
|
|
|
|
if (CONSP(more_numbers))
|
|
set_number_object(&num, number);
|
|
else {
|
|
num.complex = 0;
|
|
num.real.type = N_FIXNUM;
|
|
num.real.data.fixnum = 1;
|
|
goto div_one_argument;
|
|
}
|
|
|
|
for (;;) {
|
|
number = CAR(more_numbers);
|
|
more_numbers = CDR(more_numbers);
|
|
|
|
div_one_argument:
|
|
div_number_object(&num, number);
|
|
if (!CONSP(more_numbers))
|
|
break;
|
|
}
|
|
|
|
return (make_number_object(&num));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_OnePlus(LispBuiltin *builtin)
|
|
/*
|
|
1+ number
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *number;
|
|
|
|
number = ARGUMENT(0);
|
|
num.complex = 0;
|
|
num.real.type = N_FIXNUM;
|
|
num.real.data.fixnum = 1;
|
|
add_number_object(&num, number);
|
|
|
|
return (make_number_object(&num));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_OneMinus(LispBuiltin *builtin)
|
|
/*
|
|
1- number
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *number;
|
|
|
|
number = ARGUMENT(0);
|
|
num.complex = 0;
|
|
num.real.type = N_FIXNUM;
|
|
num.real.data.fixnum = -1;
|
|
add_number_object(&num, number);
|
|
|
|
return (make_number_object(&num));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Less(LispBuiltin *builtin)
|
|
/*
|
|
< number &rest more-numbers
|
|
*/
|
|
{
|
|
LispObj *compare, *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
compare = ARGUMENT(0);
|
|
|
|
if (CONSP(more_numbers)) {
|
|
do {
|
|
number = CAR(more_numbers);
|
|
if (cmp_object_object(compare, number, 1) >= 0)
|
|
return (NIL);
|
|
compare = number;
|
|
more_numbers = CDR(more_numbers);
|
|
} while (CONSP(more_numbers));
|
|
}
|
|
else {
|
|
CHECK_REAL(compare);
|
|
}
|
|
|
|
return (T);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_LessEqual(LispBuiltin *builtin)
|
|
/*
|
|
<= number &rest more-numbers
|
|
*/
|
|
{
|
|
LispObj *compare, *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
compare = ARGUMENT(0);
|
|
|
|
if (CONSP(more_numbers)) {
|
|
do {
|
|
number = CAR(more_numbers);
|
|
if (cmp_object_object(compare, number, 1) > 0)
|
|
return (NIL);
|
|
compare = number;
|
|
more_numbers = CDR(more_numbers);
|
|
} while (CONSP(more_numbers));
|
|
}
|
|
else {
|
|
CHECK_REAL(compare);
|
|
}
|
|
|
|
return (T);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Equal_(LispBuiltin *builtin)
|
|
/*
|
|
= number &rest more-numbers
|
|
*/
|
|
{
|
|
LispObj *compare, *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
compare = ARGUMENT(0);
|
|
|
|
if (CONSP(more_numbers)) {
|
|
do {
|
|
number = CAR(more_numbers);
|
|
if (cmp_object_object(compare, number, 0) != 0)
|
|
return (NIL);
|
|
compare = number;
|
|
more_numbers = CDR(more_numbers);
|
|
} while (CONSP(more_numbers));
|
|
}
|
|
else {
|
|
CHECK_REAL(compare);
|
|
}
|
|
|
|
return (T);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Greater(LispBuiltin *builtin)
|
|
/*
|
|
> number &rest more-numbers
|
|
*/
|
|
{
|
|
LispObj *compare, *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
compare = ARGUMENT(0);
|
|
|
|
if (CONSP(more_numbers)) {
|
|
do {
|
|
number = CAR(more_numbers);
|
|
if (cmp_object_object(compare, number, 1) <= 0)
|
|
return (NIL);
|
|
compare = number;
|
|
more_numbers = CDR(more_numbers);
|
|
} while (CONSP(more_numbers));
|
|
}
|
|
else {
|
|
CHECK_REAL(compare);
|
|
}
|
|
|
|
return (T);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_GreaterEqual(LispBuiltin *builtin)
|
|
/*
|
|
>= number &rest more-numbers
|
|
*/
|
|
{
|
|
LispObj *compare, *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
compare = ARGUMENT(0);
|
|
|
|
if (CONSP(more_numbers)) {
|
|
do {
|
|
number = CAR(more_numbers);
|
|
if (cmp_object_object(compare, number, 1) < 0)
|
|
return (NIL);
|
|
compare = number;
|
|
more_numbers = CDR(more_numbers);
|
|
} while (CONSP(more_numbers));
|
|
}
|
|
else {
|
|
CHECK_REAL(compare);
|
|
}
|
|
|
|
return (T);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_NotEqual(LispBuiltin *builtin)
|
|
/*
|
|
/= number &rest more-numbers
|
|
*/
|
|
{
|
|
LispObj *object, *compare, *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
number = ARGUMENT(0);
|
|
|
|
if (!CONSP(more_numbers)) {
|
|
CHECK_REAL(number);
|
|
|
|
return (T);
|
|
}
|
|
|
|
/* compare all numbers */
|
|
while (1) {
|
|
compare = number;
|
|
for (object = more_numbers; CONSP(object); object = CDR(object)) {
|
|
number = CAR(object);
|
|
|
|
if (cmp_object_object(compare, number, 0) == 0)
|
|
return (NIL);
|
|
}
|
|
if (CONSP(more_numbers)) {
|
|
number = CAR(more_numbers);
|
|
more_numbers = CDR(more_numbers);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
return (T);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Min(LispBuiltin *builtin)
|
|
/*
|
|
min number &rest more-numbers
|
|
*/
|
|
{
|
|
LispObj *result, *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
result = ARGUMENT(0);
|
|
|
|
if (CONSP(more_numbers)) {
|
|
do {
|
|
number = CAR(more_numbers);
|
|
if (cmp_object_object(result, number, 1) > 0)
|
|
result = number;
|
|
more_numbers = CDR(more_numbers);
|
|
} while (CONSP(more_numbers));
|
|
}
|
|
else {
|
|
CHECK_REAL(result);
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Max(LispBuiltin *builtin)
|
|
/*
|
|
max number &rest more-numbers
|
|
*/
|
|
{
|
|
LispObj *result, *number, *more_numbers;
|
|
|
|
more_numbers = ARGUMENT(1);
|
|
result = ARGUMENT(0);
|
|
|
|
if (CONSP(more_numbers)) {
|
|
do {
|
|
number = CAR(more_numbers);
|
|
if (cmp_object_object(result, number, 1) < 0)
|
|
result = number;
|
|
more_numbers = CDR(more_numbers);
|
|
} while (CONSP(more_numbers));
|
|
}
|
|
else {
|
|
CHECK_REAL(result);
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Abs(LispBuiltin *builtin)
|
|
/*
|
|
abs number
|
|
*/
|
|
{
|
|
LispObj *result, *number;
|
|
|
|
result = number = ARGUMENT(0);
|
|
|
|
switch (OBJECT_TYPE(number)) {
|
|
case LispFixnum_t:
|
|
case LispInteger_t:
|
|
case LispBignum_t:
|
|
case LispDFloat_t:
|
|
case LispRatio_t:
|
|
case LispBigratio_t:
|
|
if (cmp_real_object(&zero, number) > 0) {
|
|
n_real real;
|
|
|
|
set_real_object(&real, number);
|
|
neg_real(&real);
|
|
result = make_real_object(&real);
|
|
}
|
|
break;
|
|
case LispComplex_t: {
|
|
n_number num;
|
|
|
|
set_number_object(&num, number);
|
|
abs_number(&num);
|
|
result = make_number_object(&num);
|
|
} break;
|
|
default:
|
|
fatal_builtin_object_error(builtin, number, NOT_A_NUMBER);
|
|
break;
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Complex(LispBuiltin *builtin)
|
|
/*
|
|
complex realpart &optional imagpart
|
|
*/
|
|
{
|
|
LispObj *realpart, *imagpart;
|
|
|
|
imagpart = ARGUMENT(1);
|
|
realpart = ARGUMENT(0);
|
|
|
|
CHECK_REAL(realpart);
|
|
|
|
if (imagpart == UNSPEC)
|
|
return (realpart);
|
|
else {
|
|
CHECK_REAL(imagpart);
|
|
}
|
|
if (!FLOATP(imagpart) && cmp_real_object(&zero, imagpart) == 0)
|
|
return (realpart);
|
|
|
|
return (COMPLEX(realpart, imagpart));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Complexp(LispBuiltin *builtin)
|
|
/*
|
|
complexp object
|
|
*/
|
|
{
|
|
LispObj *object;
|
|
|
|
object = ARGUMENT(0);
|
|
|
|
return (COMPLEXP(object) ? T : NIL);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Conjugate(LispBuiltin *builtin)
|
|
/*
|
|
conjugate number
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *number, *realpart, *imagpart;
|
|
|
|
number = ARGUMENT(0);
|
|
|
|
CHECK_NUMBER(number);
|
|
|
|
if (REALP(number))
|
|
return (number);
|
|
|
|
realpart = OCXR(number);
|
|
num.complex = 0;
|
|
num.real.type = N_FIXNUM;
|
|
num.real.data.fixnum = -1;
|
|
mul_number_object(&num, OCXI(number));
|
|
imagpart = make_number_object(&num);
|
|
|
|
return (COMPLEX(realpart, imagpart));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Decf(LispBuiltin *builtin)
|
|
/*
|
|
decf place &optional delta
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *place, *delta, *number;
|
|
|
|
delta = ARGUMENT(1);
|
|
place = ARGUMENT(0);
|
|
|
|
if (SYMBOLP(place)) {
|
|
number = LispGetVar(place);
|
|
if (number == NULL)
|
|
LispDestroy("EVAL: the variable %s is unbound", STROBJ(place));
|
|
}
|
|
else
|
|
number = EVAL(place);
|
|
|
|
if (delta != UNSPEC) {
|
|
LispObj *operand;
|
|
|
|
operand = EVAL(delta);
|
|
set_number_object(&num, number);
|
|
sub_number_object(&num, operand);
|
|
number = make_number_object(&num);
|
|
}
|
|
else {
|
|
num.complex = 0;
|
|
num.real.type = N_FIXNUM;
|
|
num.real.data.fixnum = -1;
|
|
add_number_object(&num, number);
|
|
number = make_number_object(&num);
|
|
}
|
|
|
|
if (SYMBOLP(place)) {
|
|
CHECK_CONSTANT(place);
|
|
LispSetVar(place, number);
|
|
}
|
|
else {
|
|
GC_ENTER();
|
|
|
|
GC_PROTECT(number);
|
|
(void)APPLY2(Osetf, place, number);
|
|
GC_LEAVE();
|
|
}
|
|
|
|
return (number);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Denominator(LispBuiltin *builtin)
|
|
/*
|
|
denominator rational
|
|
*/
|
|
{
|
|
LispObj *result, *rational;
|
|
|
|
rational = ARGUMENT(0);
|
|
|
|
switch (OBJECT_TYPE(rational)) {
|
|
case LispFixnum_t:
|
|
case LispInteger_t:
|
|
case LispBignum_t:
|
|
result = FIXNUM(1);
|
|
break;
|
|
case LispRatio_t:
|
|
result = INTEGER(OFRD(rational));
|
|
break;
|
|
case LispBigratio_t:
|
|
if (mpi_fiti(OBRD(rational)))
|
|
result = INTEGER(mpi_geti(OBRD(rational)));
|
|
else {
|
|
mpi *den = XALLOC(mpi);
|
|
|
|
mpi_init(den);
|
|
mpi_set(den, OBRD(rational));
|
|
result = BIGNUM(den);
|
|
}
|
|
break;
|
|
default:
|
|
LispDestroy("%s: %s is not a rational number",
|
|
STRFUN(builtin), STROBJ(rational));
|
|
/*NOTREACHED*/
|
|
result = NIL;
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Evenp(LispBuiltin *builtin)
|
|
/*
|
|
evenp integer
|
|
*/
|
|
{
|
|
LispObj *result, *integer;
|
|
|
|
integer = ARGUMENT(0);
|
|
|
|
switch (OBJECT_TYPE(integer)) {
|
|
case LispFixnum_t:
|
|
result = FIXNUM_VALUE(integer) % 2 ? NIL : T;
|
|
break;
|
|
case LispInteger_t:
|
|
result = INT_VALUE(integer) % 2 ? NIL : T;
|
|
break;
|
|
case LispBignum_t:
|
|
result = mpi_remi(OBI(integer), 2) ? NIL : T;
|
|
break;
|
|
default:
|
|
fatal_builtin_object_error(builtin, integer, NOT_AN_INTEGER);
|
|
/*NOTREACHED*/
|
|
result = NIL;
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
/* only one float format */
|
|
LispObj *
|
|
Lisp_Float(LispBuiltin *builtin)
|
|
/*
|
|
float number &optional other
|
|
*/
|
|
{
|
|
LispObj *number, *other;
|
|
|
|
other = ARGUMENT(1);
|
|
number = ARGUMENT(0);
|
|
|
|
if (other != UNSPEC) {
|
|
CHECK_DFLOAT(other);
|
|
}
|
|
|
|
return (LispFloatCoerce(builtin, number));
|
|
}
|
|
|
|
LispObj *
|
|
LispFloatCoerce(LispBuiltin *builtin, LispObj *number)
|
|
{
|
|
double value;
|
|
|
|
switch (OBJECT_TYPE(number)) {
|
|
case LispFixnum_t:
|
|
value = FIXNUM_VALUE(number);
|
|
break;
|
|
case LispInteger_t:
|
|
value = INT_VALUE(number);
|
|
break;
|
|
case LispBignum_t:
|
|
value = mpi_getd(OBI(number));
|
|
break;
|
|
case LispDFloat_t:
|
|
return (number);
|
|
case LispRatio_t:
|
|
value = (double)OFRN(number) / (double)OFRD(number);
|
|
break;
|
|
case LispBigratio_t:
|
|
value = mpr_getd(OBR(number));
|
|
break;
|
|
default:
|
|
value = 0.0;
|
|
fatal_builtin_object_error(builtin, number, NOT_A_REAL_NUMBER);
|
|
break;
|
|
}
|
|
|
|
if (!finite(value))
|
|
fatal_error(FLOATING_POINT_OVERFLOW);
|
|
|
|
return (DFLOAT(value));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Floatp(LispBuiltin *builtin)
|
|
/*
|
|
floatp object
|
|
*/
|
|
{
|
|
LispObj *object;
|
|
|
|
object = ARGUMENT(0);
|
|
|
|
return (FLOATP(object) ? T : NIL);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Gcd(LispBuiltin *builtin)
|
|
/*
|
|
gcd &rest integers
|
|
*/
|
|
{
|
|
n_real real;
|
|
LispObj *integers, *integer, *operand;
|
|
|
|
integers = ARGUMENT(0);
|
|
|
|
if (!CONSP(integers))
|
|
return (FIXNUM(0));
|
|
|
|
integer = CAR(integers);
|
|
|
|
CHECK_INTEGER(integer);
|
|
set_real_object(&real, integer);
|
|
integers = CDR(integers);
|
|
|
|
for (; CONSP(integers); integers = CDR(integers)) {
|
|
operand = CAR(integers);
|
|
gcd_real_object(&real, operand);
|
|
}
|
|
abs_real(&real);
|
|
|
|
return (make_real_object(&real));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Imagpart(LispBuiltin *builtin)
|
|
/*
|
|
imagpart number
|
|
*/
|
|
{
|
|
LispObj *number;
|
|
|
|
number = ARGUMENT(0);
|
|
|
|
if (COMPLEXP(number))
|
|
return (OCXI(number));
|
|
else {
|
|
CHECK_REAL(number);
|
|
}
|
|
|
|
return (FIXNUM(0));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Incf(LispBuiltin *builtin)
|
|
/*
|
|
incf place &optional delta
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *place, *delta, *number;
|
|
|
|
delta = ARGUMENT(1);
|
|
place = ARGUMENT(0);
|
|
|
|
if (SYMBOLP(place)) {
|
|
number = LispGetVar(place);
|
|
if (number == NULL)
|
|
LispDestroy("EVAL: the variable %s is unbound", STROBJ(place));
|
|
}
|
|
else
|
|
number = EVAL(place);
|
|
|
|
if (delta != UNSPEC) {
|
|
LispObj *operand;
|
|
|
|
operand = EVAL(delta);
|
|
set_number_object(&num, number);
|
|
add_number_object(&num, operand);
|
|
number = make_number_object(&num);
|
|
}
|
|
else {
|
|
num.complex = 0;
|
|
num.real.type = N_FIXNUM;
|
|
num.real.data.fixnum = 1;
|
|
add_number_object(&num, number);
|
|
number = make_number_object(&num);
|
|
}
|
|
|
|
if (SYMBOLP(place)) {
|
|
CHECK_CONSTANT(place);
|
|
LispSetVar(place, number);
|
|
}
|
|
else {
|
|
GC_ENTER();
|
|
|
|
GC_PROTECT(number);
|
|
(void)APPLY2(Osetf, place, number);
|
|
GC_LEAVE();
|
|
}
|
|
|
|
return (number);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Integerp(LispBuiltin *builtin)
|
|
/*
|
|
integerp object
|
|
*/
|
|
{
|
|
LispObj *object;
|
|
|
|
object = ARGUMENT(0);
|
|
|
|
return (INTEGERP(object) ? T : NIL);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Isqrt(LispBuiltin *builtin)
|
|
/*
|
|
isqrt natural
|
|
*/
|
|
{
|
|
LispObj *natural, *result;
|
|
|
|
natural = ARGUMENT(0);
|
|
|
|
if (cmp_object_object(natural, obj_zero, 1) < 0)
|
|
goto not_a_natural_number;
|
|
|
|
switch (OBJECT_TYPE(natural)) {
|
|
case LispFixnum_t:
|
|
result = FIXNUM((long)floor(sqrt(FIXNUM_VALUE(natural))));
|
|
break;
|
|
case LispInteger_t:
|
|
result = INTEGER((long)floor(sqrt(INT_VALUE(natural))));
|
|
break;
|
|
case LispBignum_t: {
|
|
mpi *bigi;
|
|
|
|
bigi = XALLOC(mpi);
|
|
mpi_init(bigi);
|
|
mpi_sqrt(bigi, OBI(natural));
|
|
if (mpi_fiti(bigi)) {
|
|
result = INTEGER(mpi_geti(bigi));
|
|
mpi_clear(bigi);
|
|
XFREE(bigi);
|
|
}
|
|
else
|
|
result = BIGNUM(bigi);
|
|
} break;
|
|
default:
|
|
goto not_a_natural_number;
|
|
}
|
|
|
|
return (result);
|
|
|
|
not_a_natural_number:
|
|
LispDestroy("%s: %s is not a natural number",
|
|
STRFUN(builtin), STROBJ(natural));
|
|
/*NOTREACHED*/
|
|
return (NIL);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Lcm(LispBuiltin *builtin)
|
|
/*
|
|
lcm &rest integers
|
|
*/
|
|
{
|
|
n_real real, gcd;
|
|
LispObj *integers, *operand;
|
|
|
|
integers = ARGUMENT(0);
|
|
|
|
if (!CONSP(integers))
|
|
return (FIXNUM(1));
|
|
|
|
operand = CAR(integers);
|
|
|
|
CHECK_INTEGER(operand);
|
|
set_real_object(&real, operand);
|
|
integers = CDR(integers);
|
|
|
|
gcd.type = N_FIXNUM;
|
|
gcd.data.fixnum = 0;
|
|
|
|
for (; CONSP(integers); integers = CDR(integers)) {
|
|
operand = CAR(integers);
|
|
|
|
if (real.type == N_FIXNUM && real.data.fixnum == 0)
|
|
break;
|
|
|
|
/* calculate gcd before changing integer */
|
|
clear_real(&gcd);
|
|
set_real_real(&gcd, &real);
|
|
gcd_real_object(&gcd, operand);
|
|
|
|
/* calculate lcm */
|
|
mul_real_object(&real, operand);
|
|
div_real_real(&real, &gcd);
|
|
}
|
|
clear_real(&gcd);
|
|
abs_real(&real);
|
|
|
|
return (make_real_object(&real));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Logand(LispBuiltin *builtin)
|
|
/*
|
|
logand &rest integers
|
|
*/
|
|
{
|
|
n_real real;
|
|
|
|
LispObj *integers;
|
|
|
|
integers = ARGUMENT(0);
|
|
|
|
real.type = N_FIXNUM;
|
|
real.data.fixnum = -1;
|
|
|
|
for (; CONSP(integers); integers = CDR(integers))
|
|
and_real_object(&real, CAR(integers));
|
|
|
|
return (make_real_object(&real));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Logeqv(LispBuiltin *builtin)
|
|
/*
|
|
logeqv &rest integers
|
|
*/
|
|
{
|
|
n_real real;
|
|
|
|
LispObj *integers;
|
|
|
|
integers = ARGUMENT(0);
|
|
|
|
real.type = N_FIXNUM;
|
|
real.data.fixnum = -1;
|
|
|
|
for (; CONSP(integers); integers = CDR(integers))
|
|
eqv_real_object(&real, CAR(integers));
|
|
|
|
return (make_real_object(&real));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Logior(LispBuiltin *builtin)
|
|
/*
|
|
logior &rest integers
|
|
*/
|
|
{
|
|
n_real real;
|
|
|
|
LispObj *integers;
|
|
|
|
integers = ARGUMENT(0);
|
|
|
|
real.type = N_FIXNUM;
|
|
real.data.fixnum = 0;
|
|
|
|
for (; CONSP(integers); integers = CDR(integers))
|
|
ior_real_object(&real, CAR(integers));
|
|
|
|
return (make_real_object(&real));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Lognot(LispBuiltin *builtin)
|
|
/*
|
|
lognot integer
|
|
*/
|
|
{
|
|
n_real real;
|
|
|
|
LispObj *integer;
|
|
|
|
integer = ARGUMENT(0);
|
|
|
|
CHECK_INTEGER(integer);
|
|
|
|
set_real_object(&real, integer);
|
|
not_real(&real);
|
|
|
|
return (make_real_object(&real));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Logxor(LispBuiltin *builtin)
|
|
/*
|
|
logxor &rest integers
|
|
*/
|
|
{
|
|
n_real real;
|
|
|
|
LispObj *integers;
|
|
|
|
integers = ARGUMENT(0);
|
|
|
|
real.type = N_FIXNUM;
|
|
real.data.fixnum = 0;
|
|
|
|
for (; CONSP(integers); integers = CDR(integers))
|
|
xor_real_object(&real, CAR(integers));
|
|
|
|
return (make_real_object(&real));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Minusp(LispBuiltin *builtin)
|
|
/*
|
|
minusp number
|
|
*/
|
|
{
|
|
LispObj *number;
|
|
|
|
number = ARGUMENT(0);
|
|
|
|
CHECK_REAL(number);
|
|
|
|
return (cmp_real_object(&zero, number) > 0 ? T : NIL);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Mod(LispBuiltin *builtin)
|
|
/*
|
|
mod number divisor
|
|
*/
|
|
{
|
|
LispObj *result;
|
|
|
|
LispObj *number, *divisor;
|
|
|
|
divisor = ARGUMENT(1);
|
|
number = ARGUMENT(0);
|
|
|
|
if (INTEGERP(number) && INTEGERP(divisor)) {
|
|
n_real real;
|
|
|
|
set_real_object(&real, number);
|
|
mod_real_object(&real, divisor);
|
|
result = make_real_object(&real);
|
|
}
|
|
else {
|
|
n_number num;
|
|
|
|
set_number_object(&num, number);
|
|
divide_number_object(&num, divisor, NDIVIDE_FLOOR, 0);
|
|
result = make_real_object(&(num.imag));
|
|
clear_real(&(num.real));
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Numberp(LispBuiltin *builtin)
|
|
/*
|
|
numberp object
|
|
*/
|
|
{
|
|
LispObj *object;
|
|
|
|
object = ARGUMENT(0);
|
|
|
|
return (NUMBERP(object) ? T : NIL);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Numerator(LispBuiltin *builtin)
|
|
/*
|
|
numerator rational
|
|
*/
|
|
{
|
|
LispObj *result, *rational;
|
|
|
|
rational = ARGUMENT(0);
|
|
|
|
switch (OBJECT_TYPE(rational)) {
|
|
case LispFixnum_t:
|
|
case LispInteger_t:
|
|
case LispBignum_t:
|
|
result = rational;
|
|
break;
|
|
case LispRatio_t:
|
|
result = INTEGER(OFRN(rational));
|
|
break;
|
|
case LispBigratio_t:
|
|
if (mpi_fiti(OBRN(rational)))
|
|
result = INTEGER(mpi_geti(OBRN(rational)));
|
|
else {
|
|
mpi *num = XALLOC(mpi);
|
|
|
|
mpi_init(num);
|
|
mpi_set(num, OBRN(rational));
|
|
result = BIGNUM(num);
|
|
}
|
|
break;
|
|
default:
|
|
LispDestroy("%s: %s is not a rational number",
|
|
STRFUN(builtin), STROBJ(rational));
|
|
/*NOTREACHED*/
|
|
result = NIL;
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Oddp(LispBuiltin *builtin)
|
|
/*
|
|
oddp integer
|
|
*/
|
|
{
|
|
LispObj *result, *integer;
|
|
|
|
integer = ARGUMENT(0);
|
|
|
|
switch (OBJECT_TYPE(integer)) {
|
|
case LispFixnum_t:
|
|
result = FIXNUM_VALUE(integer) % 2 ? T : NIL;
|
|
break;
|
|
case LispInteger_t:
|
|
result = INT_VALUE(integer) % 2 ? T : NIL;
|
|
break;
|
|
case LispBignum_t:
|
|
result = mpi_remi(OBI(integer), 2) ? T : NIL;
|
|
break;
|
|
default:
|
|
fatal_builtin_object_error(builtin, integer, NOT_AN_INTEGER);
|
|
/*NOTREACHED*/
|
|
result = NIL;
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Plusp(LispBuiltin *builtin)
|
|
/*
|
|
plusp number
|
|
*/
|
|
{
|
|
LispObj *number;
|
|
|
|
number = ARGUMENT(0);
|
|
|
|
CHECK_REAL(number);
|
|
|
|
return (cmp_real_object(&zero, number) < 0 ? T : NIL);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Rational(LispBuiltin *builtin)
|
|
/*
|
|
rational number
|
|
*/
|
|
{
|
|
LispObj *number;
|
|
|
|
number = ARGUMENT(0);
|
|
|
|
if (DFLOATP(number)) {
|
|
double numerator = ODF(number);
|
|
|
|
if ((long)numerator == numerator)
|
|
number = INTEGER(numerator);
|
|
else {
|
|
n_real real;
|
|
mpr *bigr = XALLOC(mpr);
|
|
|
|
mpr_init(bigr);
|
|
mpr_setd(bigr, numerator);
|
|
real.type = N_BIGRATIO;
|
|
real.data.bigratio = bigr;
|
|
rbr_canonicalize(&real);
|
|
number = make_real_object(&real);
|
|
}
|
|
}
|
|
else {
|
|
CHECK_REAL(number);
|
|
}
|
|
|
|
return (number);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Rationalp(LispBuiltin *builtin)
|
|
/*
|
|
rationalp object
|
|
*/
|
|
{
|
|
LispObj *object;
|
|
|
|
object = ARGUMENT(0);
|
|
|
|
return (RATIONALP(object) ? T : NIL);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Realpart(LispBuiltin *builtin)
|
|
/*
|
|
realpart number
|
|
*/
|
|
{
|
|
LispObj *number;
|
|
|
|
number = ARGUMENT(0);
|
|
|
|
if (COMPLEXP(number))
|
|
return (OCXR(number));
|
|
else {
|
|
CHECK_REAL(number);
|
|
}
|
|
|
|
return (number);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Rem(LispBuiltin *builtin)
|
|
/*
|
|
rem number divisor
|
|
*/
|
|
{
|
|
LispObj *result;
|
|
|
|
LispObj *number, *divisor;
|
|
|
|
divisor = ARGUMENT(1);
|
|
number = ARGUMENT(0);
|
|
|
|
if (INTEGERP(number) && INTEGERP(divisor)) {
|
|
n_real real;
|
|
|
|
set_real_object(&real, number);
|
|
rem_real_object(&real, divisor);
|
|
result = make_real_object(&real);
|
|
}
|
|
else {
|
|
n_number num;
|
|
|
|
set_number_object(&num, number);
|
|
divide_number_object(&num, divisor, NDIVIDE_TRUNC, 0);
|
|
result = make_real_object(&(num.imag));
|
|
clear_real(&(num.real));
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Sqrt(LispBuiltin *builtin)
|
|
/*
|
|
sqrt number
|
|
*/
|
|
{
|
|
n_number num;
|
|
LispObj *number;
|
|
|
|
number = ARGUMENT(0);
|
|
|
|
set_number_object(&num, number);
|
|
sqrt_number(&num);
|
|
|
|
return (make_number_object(&num));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Zerop(LispBuiltin *builtin)
|
|
/*
|
|
zerop number
|
|
*/
|
|
{
|
|
LispObj *result, *number;
|
|
|
|
number = ARGUMENT(0);
|
|
|
|
switch (OBJECT_TYPE(number)) {
|
|
case LispFixnum_t:
|
|
case LispInteger_t:
|
|
case LispBignum_t:
|
|
case LispDFloat_t:
|
|
case LispRatio_t:
|
|
case LispBigratio_t:
|
|
result = cmp_real_object(&zero, number) == 0 ? T : NIL;
|
|
break;
|
|
case LispComplex_t:
|
|
result = cmp_real_object(&zero, OCXR(number)) == 0 &&
|
|
cmp_real_object(&zero, OCXI(number)) == 0 ? T : NIL;
|
|
break;
|
|
default:
|
|
fatal_builtin_object_error(builtin, number, NOT_A_NUMBER);
|
|
/*NOTREACHED*/
|
|
result = NIL;
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
static LispObj *
|
|
LispDivide(LispBuiltin *builtin, int fun, int flo)
|
|
{
|
|
n_number num;
|
|
LispObj *number, *divisor;
|
|
|
|
divisor = ARGUMENT(1);
|
|
number = ARGUMENT(0);
|
|
|
|
RETURN_COUNT = 1;
|
|
|
|
if (cmp_real_object(&zero, number) == 0) {
|
|
if (divisor != NIL) {
|
|
CHECK_REAL(divisor);
|
|
}
|
|
|
|
return (RETURN(0) = obj_zero);
|
|
}
|
|
|
|
if (divisor == UNSPEC)
|
|
divisor = obj_one;
|
|
|
|
set_number_object(&num, number);
|
|
if (num.complex)
|
|
fatal_builtin_object_error(builtin, divisor, NOT_A_REAL_NUMBER);
|
|
|
|
divide_number_object(&num, divisor, fun, flo);
|
|
RETURN(0) = make_real_object(&(num.imag));
|
|
|
|
return (make_real_object(&(num.real)));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Ceiling(LispBuiltin *builtin)
|
|
/*
|
|
ceiling number &optional divisor
|
|
*/
|
|
{
|
|
return (LispDivide(builtin, NDIVIDE_CEIL, 0));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Fceiling(LispBuiltin *builtin)
|
|
/*
|
|
fceiling number &optional divisor
|
|
*/
|
|
{
|
|
return (LispDivide(builtin, NDIVIDE_CEIL, 1));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Floor(LispBuiltin *builtin)
|
|
/*
|
|
floor number &optional divisor
|
|
*/
|
|
{
|
|
return (LispDivide(builtin, NDIVIDE_FLOOR, 0));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Ffloor(LispBuiltin *builtin)
|
|
/*
|
|
ffloor number &optional divisor
|
|
*/
|
|
{
|
|
return (LispDivide(builtin, NDIVIDE_FLOOR, 1));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Round(LispBuiltin *builtin)
|
|
/*
|
|
round number &optional divisor
|
|
*/
|
|
{
|
|
return (LispDivide(builtin, NDIVIDE_ROUND, 0));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Fround(LispBuiltin *builtin)
|
|
/*
|
|
fround number &optional divisor
|
|
*/
|
|
{
|
|
return (LispDivide(builtin, NDIVIDE_ROUND, 1));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Truncate(LispBuiltin *builtin)
|
|
/*
|
|
truncate number &optional divisor
|
|
*/
|
|
{
|
|
return (LispDivide(builtin, NDIVIDE_TRUNC, 0));
|
|
}
|
|
|
|
LispObj *
|
|
Lisp_Ftruncate(LispBuiltin *builtin)
|
|
/*
|
|
ftruncate number &optional divisor
|
|
*/
|
|
{
|
|
return (LispDivide(builtin, NDIVIDE_TRUNC, 1));
|
|
}
|