Logo Search packages:      
Sourcecode: x11-apps version File versions  Download package

math.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));
}

Generated by  Doxygen 1.6.0   Back to index