/* * 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" #if defined(__UNIXOS2__) || defined(__arm64__) # 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->value); 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)); }