Edit

IABSD.fr/xenocara/app/xedit/lisp/math.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-25 20:07:29
    Hash : 616b6f15
    Message : Importing from X.Org 7.2RC2

  • app/xedit/lisp/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));
    }