diff options
Diffstat (limited to 'lisp/math.c')
-rw-r--r-- | lisp/math.c | 1473 |
1 files changed, 1473 insertions, 0 deletions
diff --git a/lisp/math.c b/lisp/math.c new file mode 100644 index 0000000..fcadefa --- /dev/null +++ b/lisp/math.c @@ -0,0 +1,1473 @@ +/* + * 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.22 2002/11/23 21:41:52 paulo Exp $ */ + +#include "math.h" +#include "private.h" + +/* + * 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 "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)); +} |