math.c revision 5dfecf96
1/*
2 * Copyright (c) 2001 by The XFree86 Project, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 * Except as contained in this notice, the name of the XFree86 Project shall
23 * not be used in advertising or otherwise to promote the sale, use or other
24 * dealings in this Software without prior written authorization from the
25 * XFree86 Project.
26 *
27 * Author: Paulo César Pereira de Andrade
28 */
29
30/* $XFree86: xc/programs/xedit/lisp/math.c,v 1.23tsi Exp $ */
31
32#include "lisp/math.h"
33#include "lisp/private.h"
34
35#ifdef __UNIXOS2__
36# define finite(x) isfinite(x)
37#endif
38
39/*
40 * Prototypes
41 */
42static LispObj *LispDivide(LispBuiltin*, int, int);
43
44/*
45 * Initialization
46 */
47static LispObj *obj_zero, *obj_one;
48LispObj *Ocomplex, *Oequal_;
49
50LispObj *Oshort_float, *Osingle_float, *Odouble_float, *Olong_float;
51
52Atom_id Sdefault_float_format;
53
54/*
55 * Implementation
56 */
57#include "lisp/mathimp.c"
58
59void
60LispMathInit(void)
61{
62    LispObj *object, *result;
63
64    mp_set_malloc(LispMalloc);
65    mp_set_calloc(LispCalloc);
66    mp_set_realloc(LispRealloc);
67    mp_set_free(LispFree);
68
69    number_init();
70    obj_zero = FIXNUM(0);
71    obj_one = FIXNUM(1);
72
73    Oequal_		= STATIC_ATOM("=");
74    Ocomplex		= STATIC_ATOM(Scomplex);
75    Oshort_float	= STATIC_ATOM("SHORT-FLOAT");
76    LispExportSymbol(Oshort_float);
77    Osingle_float	= STATIC_ATOM("SINGLE-FLOAT");
78    LispExportSymbol(Osingle_float);
79    Odouble_float	= STATIC_ATOM("DOUBLE-FLOAT");
80    LispExportSymbol(Odouble_float);
81    Olong_float		= STATIC_ATOM("LONG-FLOAT");
82    LispExportSymbol(Olong_float);
83
84    object		= STATIC_ATOM("*DEFAULT-FLOAT-FORMAT*");
85    LispProclaimSpecial(object, Odouble_float, NIL);
86    LispExportSymbol(object);
87    Sdefault_float_format = ATOMID(object);
88
89    object		= STATIC_ATOM("PI");
90    result = number_pi();
91    LispProclaimSpecial(object, result, NIL);
92    LispExportSymbol(object);
93
94    object		= STATIC_ATOM("MOST-POSITIVE-FIXNUM");
95    LispDefconstant(object, FIXNUM(MOST_POSITIVE_FIXNUM), NIL);
96    LispExportSymbol(object);
97
98    object		= STATIC_ATOM("MOST-NEGATIVE-FIXNUM");
99    LispDefconstant(object, FIXNUM(MOST_NEGATIVE_FIXNUM), NIL);
100    LispExportSymbol(object);
101}
102
103LispObj *
104Lisp_Mul(LispBuiltin *builtin)
105/*
106 * &rest numbers
107 */
108{
109    n_number num;
110    LispObj *number, *numbers;
111
112    numbers = ARGUMENT(0);
113
114    if (CONSP(numbers)) {
115	number = CAR(numbers);
116
117	numbers = CDR(numbers);
118	if (!CONSP(numbers)) {
119	    CHECK_NUMBER(number);
120	    return (number);
121	}
122    }
123    else
124	return (FIXNUM(1));
125
126    set_number_object(&num, number);
127    do {
128	mul_number_object(&num, CAR(numbers));
129	numbers = CDR(numbers);
130    } while (CONSP(numbers));
131
132    return (make_number_object(&num));
133}
134
135LispObj *
136Lisp_Plus(LispBuiltin *builtin)
137/*
138 + &rest numbers
139 */
140{
141    n_number num;
142    LispObj *number, *numbers;
143
144    numbers = ARGUMENT(0);
145
146    if (CONSP(numbers)) {
147	number = CAR(numbers);
148
149	numbers = CDR(numbers);
150	if (!CONSP(numbers)) {
151	    CHECK_NUMBER(number);
152	    return (number);
153	}
154    }
155    else
156	return (FIXNUM(0));
157
158    set_number_object(&num, number);
159    do {
160	add_number_object(&num, CAR(numbers));
161	numbers = CDR(numbers);
162    } while (CONSP(numbers));
163
164    return (make_number_object(&num));
165}
166
167LispObj *
168Lisp_Minus(LispBuiltin *builtin)
169/*
170 - number &rest more_numbers
171 */
172{
173    n_number num;
174    LispObj *number, *more_numbers;
175
176    more_numbers = ARGUMENT(1);
177    number = ARGUMENT(0);
178
179    set_number_object(&num, number);
180    if (!CONSP(more_numbers)) {
181	neg_number(&num);
182
183	return (make_number_object(&num));
184    }
185    do {
186	sub_number_object(&num, CAR(more_numbers));
187	more_numbers = CDR(more_numbers);
188    } while (CONSP(more_numbers));
189
190    return (make_number_object(&num));
191}
192
193LispObj *
194Lisp_Div(LispBuiltin *builtin)
195/*
196 / number &rest more_numbers
197 */
198{
199    n_number num;
200    LispObj *number, *more_numbers;
201
202    more_numbers = ARGUMENT(1);
203    number = ARGUMENT(0);
204
205    if (CONSP(more_numbers))
206	set_number_object(&num, number);
207    else {
208	num.complex = 0;
209	num.real.type = N_FIXNUM;
210	num.real.data.fixnum = 1;
211	goto div_one_argument;
212    }
213
214    for (;;) {
215	number = CAR(more_numbers);
216	more_numbers = CDR(more_numbers);
217
218div_one_argument:
219	div_number_object(&num, number);
220	if (!CONSP(more_numbers))
221	    break;
222    }
223
224    return (make_number_object(&num));
225}
226
227LispObj *
228Lisp_OnePlus(LispBuiltin *builtin)
229/*
230 1+ number
231 */
232{
233    n_number num;
234    LispObj *number;
235
236    number = ARGUMENT(0);
237    num.complex = 0;
238    num.real.type = N_FIXNUM;
239    num.real.data.fixnum = 1;
240    add_number_object(&num, number);
241
242    return (make_number_object(&num));
243}
244
245LispObj *
246Lisp_OneMinus(LispBuiltin *builtin)
247/*
248 1- number
249 */
250{
251    n_number num;
252    LispObj *number;
253
254    number = ARGUMENT(0);
255    num.complex = 0;
256    num.real.type = N_FIXNUM;
257    num.real.data.fixnum = -1;
258    add_number_object(&num, number);
259
260    return (make_number_object(&num));
261}
262
263LispObj *
264Lisp_Less(LispBuiltin *builtin)
265/*
266 < number &rest more-numbers
267 */
268{
269    LispObj *compare, *number, *more_numbers;
270
271    more_numbers = ARGUMENT(1);
272    compare = ARGUMENT(0);
273
274    if (CONSP(more_numbers)) {
275	do {
276	    number = CAR(more_numbers);
277	    if (cmp_object_object(compare, number, 1) >= 0)
278		return (NIL);
279	    compare = number;
280	    more_numbers = CDR(more_numbers);
281	} while (CONSP(more_numbers));
282    }
283    else {
284	CHECK_REAL(compare);
285    }
286
287    return (T);
288}
289
290LispObj *
291Lisp_LessEqual(LispBuiltin *builtin)
292/*
293 <= number &rest more-numbers
294 */
295{
296    LispObj *compare, *number, *more_numbers;
297
298    more_numbers = ARGUMENT(1);
299    compare = ARGUMENT(0);
300
301    if (CONSP(more_numbers)) {
302	do {
303	    number = CAR(more_numbers);
304	    if (cmp_object_object(compare, number, 1) > 0)
305		return (NIL);
306	    compare = number;
307	    more_numbers = CDR(more_numbers);
308	} while (CONSP(more_numbers));
309    }
310    else {
311	CHECK_REAL(compare);
312    }
313
314    return (T);
315}
316
317LispObj *
318Lisp_Equal_(LispBuiltin *builtin)
319/*
320 = number &rest more-numbers
321 */
322{
323    LispObj *compare, *number, *more_numbers;
324
325    more_numbers = ARGUMENT(1);
326    compare = ARGUMENT(0);
327
328    if (CONSP(more_numbers)) {
329	do {
330	    number = CAR(more_numbers);
331	    if (cmp_object_object(compare, number, 0) != 0)
332		return (NIL);
333	    compare = number;
334	    more_numbers = CDR(more_numbers);
335	} while (CONSP(more_numbers));
336    }
337    else {
338	CHECK_REAL(compare);
339    }
340
341    return (T);
342}
343
344LispObj *
345Lisp_Greater(LispBuiltin *builtin)
346/*
347 > number &rest more-numbers
348 */
349{
350    LispObj *compare, *number, *more_numbers;
351
352    more_numbers = ARGUMENT(1);
353    compare = ARGUMENT(0);
354
355    if (CONSP(more_numbers)) {
356	do {
357	    number = CAR(more_numbers);
358	    if (cmp_object_object(compare, number, 1) <= 0)
359		return (NIL);
360	    compare = number;
361	    more_numbers = CDR(more_numbers);
362	} while (CONSP(more_numbers));
363    }
364    else {
365	CHECK_REAL(compare);
366    }
367
368    return (T);
369}
370
371LispObj *
372Lisp_GreaterEqual(LispBuiltin *builtin)
373/*
374 >= number &rest more-numbers
375 */
376{
377    LispObj *compare, *number, *more_numbers;
378
379    more_numbers = ARGUMENT(1);
380    compare = ARGUMENT(0);
381
382    if (CONSP(more_numbers)) {
383	do {
384	    number = CAR(more_numbers);
385	    if (cmp_object_object(compare, number, 1) < 0)
386		return (NIL);
387	    compare = number;
388	    more_numbers = CDR(more_numbers);
389	} while (CONSP(more_numbers));
390    }
391    else {
392	CHECK_REAL(compare);
393    }
394
395    return (T);
396}
397
398LispObj *
399Lisp_NotEqual(LispBuiltin *builtin)
400/*
401 /= number &rest more-numbers
402 */
403{
404    LispObj *object, *compare, *number, *more_numbers;
405
406    more_numbers = ARGUMENT(1);
407    number = ARGUMENT(0);
408
409    if (!CONSP(more_numbers)) {
410	CHECK_REAL(number);
411
412	return (T);
413    }
414
415    /* compare all numbers */
416    while (1) {
417	compare = number;
418	for (object = more_numbers; CONSP(object); object = CDR(object)) {
419	    number = CAR(object);
420
421	    if (cmp_object_object(compare, number, 0) == 0)
422		return (NIL);
423	}
424	if (CONSP(more_numbers)) {
425	    number = CAR(more_numbers);
426	    more_numbers = CDR(more_numbers);
427	}
428	else
429	    break;
430    }
431
432    return (T);
433}
434
435LispObj *
436Lisp_Min(LispBuiltin *builtin)
437/*
438 min number &rest more-numbers
439 */
440{
441    LispObj *result, *number, *more_numbers;
442
443    more_numbers = ARGUMENT(1);
444    result = ARGUMENT(0);
445
446    if (CONSP(more_numbers)) {
447	do {
448	    number = CAR(more_numbers);
449	    if (cmp_object_object(result, number, 1) > 0)
450		result = number;
451	    more_numbers = CDR(more_numbers);
452	} while (CONSP(more_numbers));
453    }
454    else {
455	CHECK_REAL(result);
456    }
457
458    return (result);
459}
460
461LispObj *
462Lisp_Max(LispBuiltin *builtin)
463/*
464 max number &rest more-numbers
465 */
466{
467    LispObj *result, *number, *more_numbers;
468
469    more_numbers = ARGUMENT(1);
470    result = ARGUMENT(0);
471
472    if (CONSP(more_numbers)) {
473	do {
474	    number = CAR(more_numbers);
475	    if (cmp_object_object(result, number, 1) < 0)
476		result = number;
477	    more_numbers = CDR(more_numbers);
478	} while (CONSP(more_numbers));
479    }
480    else {
481	CHECK_REAL(result);
482    }
483
484    return (result);
485}
486
487LispObj *
488Lisp_Abs(LispBuiltin *builtin)
489/*
490 abs number
491 */
492{
493    LispObj *result, *number;
494
495    result = number = ARGUMENT(0);
496
497    switch (OBJECT_TYPE(number)) {
498	case LispFixnum_t:
499	case LispInteger_t:
500	case LispBignum_t:
501	case LispDFloat_t:
502	case LispRatio_t:
503	case LispBigratio_t:
504	    if (cmp_real_object(&zero, number) > 0) {
505		n_real real;
506
507		set_real_object(&real, number);
508		neg_real(&real);
509		result = make_real_object(&real);
510	    }
511	    break;
512	case LispComplex_t: {
513	    n_number num;
514
515	    set_number_object(&num, number);
516	    abs_number(&num);
517	    result = make_number_object(&num);
518	}   break;
519	default:
520	    fatal_builtin_object_error(builtin, number, NOT_A_NUMBER);
521	    break;
522    }
523
524    return (result);
525}
526
527LispObj *
528Lisp_Complex(LispBuiltin *builtin)
529/*
530 complex realpart &optional imagpart
531 */
532{
533    LispObj *realpart, *imagpart;
534
535    imagpart = ARGUMENT(1);
536    realpart = ARGUMENT(0);
537
538    CHECK_REAL(realpart);
539
540    if (imagpart == UNSPEC)
541	return (realpart);
542    else {
543	CHECK_REAL(imagpart);
544    }
545    if (!FLOATP(imagpart) && cmp_real_object(&zero, imagpart) == 0)
546	return (realpart);
547
548    return (COMPLEX(realpart, imagpart));
549}
550
551LispObj *
552Lisp_Complexp(LispBuiltin *builtin)
553/*
554 complexp object
555 */
556{
557    LispObj *object;
558
559    object = ARGUMENT(0);
560
561    return (COMPLEXP(object) ? T : NIL);
562}
563
564LispObj *
565Lisp_Conjugate(LispBuiltin *builtin)
566/*
567 conjugate number
568 */
569{
570    n_number num;
571    LispObj *number, *realpart, *imagpart;
572
573    number = ARGUMENT(0);
574
575    CHECK_NUMBER(number);
576
577    if (REALP(number))
578	return (number);
579
580    realpart = OCXR(number);
581    num.complex = 0;
582    num.real.type = N_FIXNUM;
583    num.real.data.fixnum = -1;
584    mul_number_object(&num, OCXI(number));
585    imagpart = make_number_object(&num);
586
587    return (COMPLEX(realpart, imagpart));
588}
589
590LispObj *
591Lisp_Decf(LispBuiltin *builtin)
592/*
593 decf place &optional delta
594 */
595{
596    n_number num;
597    LispObj *place, *delta, *number;
598
599    delta = ARGUMENT(1);
600    place = ARGUMENT(0);
601
602    if (SYMBOLP(place)) {
603	number = LispGetVar(place);
604	if (number == NULL)
605	    LispDestroy("EVAL: the variable %s is unbound", STROBJ(place));
606    }
607    else
608	number = EVAL(place);
609
610    if (delta != UNSPEC) {
611	LispObj *operand;
612
613	operand = EVAL(delta);
614	set_number_object(&num, number);
615	sub_number_object(&num, operand);
616	number = make_number_object(&num);
617    }
618    else {
619	num.complex = 0;
620	num.real.type = N_FIXNUM;
621	num.real.data.fixnum = -1;
622	add_number_object(&num, number);
623	number = make_number_object(&num);
624    }
625
626    if (SYMBOLP(place)) {
627	CHECK_CONSTANT(place);
628	LispSetVar(place, number);
629    }
630    else {
631	GC_ENTER();
632
633	GC_PROTECT(number);
634	(void)APPLY2(Osetf, place, number);
635	GC_LEAVE();
636    }
637
638    return (number);
639}
640
641LispObj *
642Lisp_Denominator(LispBuiltin *builtin)
643/*
644 denominator rational
645 */
646{
647    LispObj *result, *rational;
648
649    rational = ARGUMENT(0);
650
651    switch (OBJECT_TYPE(rational)) {
652	case LispFixnum_t:
653	case LispInteger_t:
654	case LispBignum_t:
655	    result = FIXNUM(1);
656	    break;
657	case LispRatio_t:
658	    result = INTEGER(OFRD(rational));
659	    break;
660	case LispBigratio_t:
661	    if (mpi_fiti(OBRD(rational)))
662		result = INTEGER(mpi_geti(OBRD(rational)));
663	    else {
664		mpi *den = XALLOC(mpi);
665
666		mpi_init(den);
667		mpi_set(den, OBRD(rational));
668		result = BIGNUM(den);
669	    }
670	    break;
671	default:
672	    LispDestroy("%s: %s is not a rational number",
673			STRFUN(builtin), STROBJ(rational));
674	    /*NOTREACHED*/
675	    result = NIL;
676    }
677
678    return (result);
679}
680
681LispObj *
682Lisp_Evenp(LispBuiltin *builtin)
683/*
684 evenp integer
685 */
686{
687    LispObj *result, *integer;
688
689    integer = ARGUMENT(0);
690
691    switch (OBJECT_TYPE(integer)) {
692	case LispFixnum_t:
693	    result = FIXNUM_VALUE(integer) % 2 ? NIL : T;
694	    break;
695	case LispInteger_t:
696	    result = INT_VALUE(integer) % 2 ? NIL : T;
697	    break;
698	case LispBignum_t:
699	    result = mpi_remi(OBI(integer), 2) ? NIL : T;
700	    break;
701	default:
702	    fatal_builtin_object_error(builtin, integer, NOT_AN_INTEGER);
703	    /*NOTREACHED*/
704	    result = NIL;
705    }
706
707    return (result);
708}
709
710/* only one float format */
711LispObj *
712Lisp_Float(LispBuiltin *builtin)
713/*
714 float number &optional other
715 */
716{
717    LispObj *number, *other;
718
719    other = ARGUMENT(1);
720    number = ARGUMENT(0);
721
722    if (other != UNSPEC) {
723	CHECK_DFLOAT(other);
724    }
725
726    return (LispFloatCoerce(builtin, number));
727}
728
729LispObj *
730LispFloatCoerce(LispBuiltin *builtin, LispObj *number)
731{
732    double value;
733
734    switch (OBJECT_TYPE(number)) {
735	case LispFixnum_t:
736	    value = FIXNUM_VALUE(number);
737	    break;
738	case LispInteger_t:
739	    value = INT_VALUE(number);
740	    break;
741	case LispBignum_t:
742	    value = mpi_getd(OBI(number));
743	    break;
744	case LispDFloat_t:
745	    return (number);
746	case LispRatio_t:
747	    value = (double)OFRN(number) / (double)OFRD(number);
748	    break;
749	case LispBigratio_t:
750	    value = mpr_getd(OBR(number));
751	    break;
752	default:
753	    value = 0.0;
754	    fatal_builtin_object_error(builtin, number, NOT_A_REAL_NUMBER);
755	    break;
756    }
757
758    if (!finite(value))
759	fatal_error(FLOATING_POINT_OVERFLOW);
760
761    return (DFLOAT(value));
762}
763
764LispObj *
765Lisp_Floatp(LispBuiltin *builtin)
766/*
767 floatp object
768 */
769{
770    LispObj *object;
771
772    object = ARGUMENT(0);
773
774    return (FLOATP(object) ? T : NIL);
775}
776
777LispObj *
778Lisp_Gcd(LispBuiltin *builtin)
779/*
780 gcd &rest integers
781 */
782{
783    n_real real;
784    LispObj *integers, *integer, *operand;
785
786    integers = ARGUMENT(0);
787
788    if (!CONSP(integers))
789	return (FIXNUM(0));
790
791    integer = CAR(integers);
792
793    CHECK_INTEGER(integer);
794    set_real_object(&real, integer);
795    integers = CDR(integers);
796
797    for (; CONSP(integers); integers = CDR(integers)) {
798	operand = CAR(integers);
799	gcd_real_object(&real, operand);
800    }
801    abs_real(&real);
802
803    return (make_real_object(&real));
804}
805
806LispObj *
807Lisp_Imagpart(LispBuiltin *builtin)
808/*
809 imagpart number
810 */
811{
812    LispObj *number;
813
814    number = ARGUMENT(0);
815
816    if (COMPLEXP(number))
817	return (OCXI(number));
818    else {
819	CHECK_REAL(number);
820    }
821
822    return (FIXNUM(0));
823}
824
825LispObj *
826Lisp_Incf(LispBuiltin *builtin)
827/*
828 incf place &optional delta
829 */
830{
831    n_number num;
832    LispObj *place, *delta, *number;
833
834    delta = ARGUMENT(1);
835    place = ARGUMENT(0);
836
837    if (SYMBOLP(place)) {
838	number = LispGetVar(place);
839	if (number == NULL)
840	    LispDestroy("EVAL: the variable %s is unbound", STROBJ(place));
841    }
842    else
843	number = EVAL(place);
844
845    if (delta != UNSPEC) {
846	LispObj *operand;
847
848	operand = EVAL(delta);
849	set_number_object(&num, number);
850	add_number_object(&num, operand);
851	number = make_number_object(&num);
852    }
853    else {
854	num.complex = 0;
855	num.real.type = N_FIXNUM;
856	num.real.data.fixnum = 1;
857	add_number_object(&num, number);
858	number = make_number_object(&num);
859    }
860
861    if (SYMBOLP(place)) {
862	CHECK_CONSTANT(place);
863	LispSetVar(place, number);
864    }
865    else {
866	GC_ENTER();
867
868	GC_PROTECT(number);
869	(void)APPLY2(Osetf, place, number);
870	GC_LEAVE();
871    }
872
873    return (number);
874}
875
876LispObj *
877Lisp_Integerp(LispBuiltin *builtin)
878/*
879 integerp object
880 */
881{
882    LispObj *object;
883
884    object = ARGUMENT(0);
885
886    return (INTEGERP(object) ? T : NIL);
887}
888
889LispObj *
890Lisp_Isqrt(LispBuiltin *builtin)
891/*
892 isqrt natural
893 */
894{
895    LispObj *natural, *result;
896
897    natural = ARGUMENT(0);
898
899    if (cmp_object_object(natural, obj_zero, 1) < 0)
900	goto not_a_natural_number;
901
902    switch (OBJECT_TYPE(natural)) {
903	case LispFixnum_t:
904	    result = FIXNUM((long)floor(sqrt(FIXNUM_VALUE(natural))));
905	    break;
906	case LispInteger_t:
907	    result = INTEGER((long)floor(sqrt(INT_VALUE(natural))));
908	    break;
909	case LispBignum_t: {
910	    mpi *bigi;
911
912	    bigi = XALLOC(mpi);
913	    mpi_init(bigi);
914	    mpi_sqrt(bigi, OBI(natural));
915	    if (mpi_fiti(bigi)) {
916		result = INTEGER(mpi_geti(bigi));
917		mpi_clear(bigi);
918		XFREE(bigi);
919	    }
920	    else
921		result = BIGNUM(bigi);
922	}   break;
923	default:
924	    goto not_a_natural_number;
925    }
926
927    return (result);
928
929not_a_natural_number:
930    LispDestroy("%s: %s is not a natural number",
931		STRFUN(builtin), STROBJ(natural));
932    /*NOTREACHED*/
933    return (NIL);
934}
935
936LispObj *
937Lisp_Lcm(LispBuiltin *builtin)
938/*
939 lcm &rest integers
940 */
941{
942    n_real real, gcd;
943    LispObj *integers, *operand;
944
945    integers = ARGUMENT(0);
946
947    if (!CONSP(integers))
948	return (FIXNUM(1));
949
950    operand = CAR(integers);
951
952    CHECK_INTEGER(operand);
953    set_real_object(&real, operand);
954    integers = CDR(integers);
955
956    gcd.type = N_FIXNUM;
957    gcd.data.fixnum = 0;
958
959    for (; CONSP(integers); integers = CDR(integers)) {
960	operand = CAR(integers);
961
962	if (real.type == N_FIXNUM && real.data.fixnum == 0)
963	    break;
964
965	/* calculate gcd before changing integer */
966	clear_real(&gcd);
967	set_real_real(&gcd, &real);
968	gcd_real_object(&gcd, operand);
969
970	/* calculate lcm */
971	mul_real_object(&real, operand);
972	div_real_real(&real, &gcd);
973    }
974    clear_real(&gcd);
975    abs_real(&real);
976
977    return (make_real_object(&real));
978}
979
980LispObj *
981Lisp_Logand(LispBuiltin *builtin)
982/*
983 logand &rest integers
984 */
985{
986    n_real real;
987
988    LispObj *integers;
989
990    integers = ARGUMENT(0);
991
992    real.type = N_FIXNUM;
993    real.data.fixnum = -1;
994
995    for (; CONSP(integers); integers = CDR(integers))
996	and_real_object(&real, CAR(integers));
997
998    return (make_real_object(&real));
999}
1000
1001LispObj *
1002Lisp_Logeqv(LispBuiltin *builtin)
1003/*
1004 logeqv &rest integers
1005 */
1006{
1007    n_real real;
1008
1009    LispObj *integers;
1010
1011    integers = ARGUMENT(0);
1012
1013    real.type = N_FIXNUM;
1014    real.data.fixnum = -1;
1015
1016    for (; CONSP(integers); integers = CDR(integers))
1017	eqv_real_object(&real, CAR(integers));
1018
1019    return (make_real_object(&real));
1020}
1021
1022LispObj *
1023Lisp_Logior(LispBuiltin *builtin)
1024/*
1025 logior &rest integers
1026 */
1027{
1028    n_real real;
1029
1030    LispObj *integers;
1031
1032    integers = ARGUMENT(0);
1033
1034    real.type = N_FIXNUM;
1035    real.data.fixnum = 0;
1036
1037    for (; CONSP(integers); integers = CDR(integers))
1038	ior_real_object(&real, CAR(integers));
1039
1040    return (make_real_object(&real));
1041}
1042
1043LispObj *
1044Lisp_Lognot(LispBuiltin *builtin)
1045/*
1046 lognot integer
1047 */
1048{
1049    n_real real;
1050
1051    LispObj *integer;
1052
1053    integer = ARGUMENT(0);
1054
1055    CHECK_INTEGER(integer);
1056
1057    set_real_object(&real, integer);
1058    not_real(&real);
1059
1060    return (make_real_object(&real));
1061}
1062
1063LispObj *
1064Lisp_Logxor(LispBuiltin *builtin)
1065/*
1066 logxor &rest integers
1067 */
1068{
1069    n_real real;
1070
1071    LispObj *integers;
1072
1073    integers = ARGUMENT(0);
1074
1075    real.type = N_FIXNUM;
1076    real.data.fixnum = 0;
1077
1078    for (; CONSP(integers); integers = CDR(integers))
1079	xor_real_object(&real, CAR(integers));
1080
1081    return (make_real_object(&real));
1082}
1083
1084LispObj *
1085Lisp_Minusp(LispBuiltin *builtin)
1086/*
1087 minusp number
1088 */
1089{
1090    LispObj *number;
1091
1092    number = ARGUMENT(0);
1093
1094    CHECK_REAL(number);
1095
1096    return (cmp_real_object(&zero, number) > 0 ? T : NIL);
1097}
1098
1099LispObj *
1100Lisp_Mod(LispBuiltin *builtin)
1101/*
1102 mod number divisor
1103 */
1104{
1105    LispObj *result;
1106
1107    LispObj *number, *divisor;
1108
1109    divisor = ARGUMENT(1);
1110    number = ARGUMENT(0);
1111
1112    if (INTEGERP(number) && INTEGERP(divisor)) {
1113	n_real real;
1114
1115	set_real_object(&real, number);
1116	mod_real_object(&real, divisor);
1117	result = make_real_object(&real);
1118    }
1119    else {
1120	n_number num;
1121
1122	set_number_object(&num, number);
1123	divide_number_object(&num, divisor, NDIVIDE_FLOOR, 0);
1124	result = make_real_object(&(num.imag));
1125	clear_real(&(num.real));
1126    }
1127
1128    return (result);
1129}
1130
1131LispObj *
1132Lisp_Numberp(LispBuiltin *builtin)
1133/*
1134 numberp object
1135 */
1136{
1137    LispObj *object;
1138
1139    object = ARGUMENT(0);
1140
1141    return (NUMBERP(object) ? T : NIL);
1142}
1143
1144LispObj *
1145Lisp_Numerator(LispBuiltin *builtin)
1146/*
1147 numerator rational
1148 */
1149{
1150    LispObj *result, *rational;
1151
1152    rational = ARGUMENT(0);
1153
1154    switch (OBJECT_TYPE(rational)) {
1155	case LispFixnum_t:
1156	case LispInteger_t:
1157	case LispBignum_t:
1158	    result = rational;
1159	    break;
1160	case LispRatio_t:
1161	    result = INTEGER(OFRN(rational));
1162	    break;
1163	case LispBigratio_t:
1164	    if (mpi_fiti(OBRN(rational)))
1165		result = INTEGER(mpi_geti(OBRN(rational)));
1166	    else {
1167		mpi *num = XALLOC(mpi);
1168
1169		mpi_init(num);
1170		mpi_set(num, OBRN(rational));
1171		result = BIGNUM(num);
1172	    }
1173	    break;
1174	default:
1175	    LispDestroy("%s: %s is not a rational number",
1176			STRFUN(builtin), STROBJ(rational));
1177	    /*NOTREACHED*/
1178	    result = NIL;
1179    }
1180
1181    return (result);
1182}
1183
1184LispObj *
1185Lisp_Oddp(LispBuiltin *builtin)
1186/*
1187 oddp integer
1188 */
1189{
1190    LispObj *result, *integer;
1191
1192    integer = ARGUMENT(0);
1193
1194    switch (OBJECT_TYPE(integer)) {
1195	case LispFixnum_t:
1196	    result = FIXNUM_VALUE(integer) % 2 ? T : NIL;
1197	    break;
1198	case LispInteger_t:
1199	    result = INT_VALUE(integer) % 2 ? T : NIL;
1200	    break;
1201	case LispBignum_t:
1202	    result = mpi_remi(OBI(integer), 2) ? T : NIL;
1203	    break;
1204	default:
1205	    fatal_builtin_object_error(builtin, integer, NOT_AN_INTEGER);
1206	    /*NOTREACHED*/
1207	    result = NIL;
1208    }
1209
1210    return (result);
1211}
1212
1213LispObj *
1214Lisp_Plusp(LispBuiltin *builtin)
1215/*
1216 plusp number
1217 */
1218{
1219    LispObj *number;
1220
1221    number = ARGUMENT(0);
1222
1223    CHECK_REAL(number);
1224
1225    return (cmp_real_object(&zero, number) < 0 ? T : NIL);
1226}
1227
1228LispObj *
1229Lisp_Rational(LispBuiltin *builtin)
1230/*
1231 rational number
1232 */
1233{
1234    LispObj *number;
1235
1236    number = ARGUMENT(0);
1237
1238    if (DFLOATP(number)) {
1239	double numerator = ODF(number);
1240
1241	if ((long)numerator == numerator)
1242	    number = INTEGER(numerator);
1243	else {
1244	    n_real real;
1245	    mpr *bigr = XALLOC(mpr);
1246
1247	    mpr_init(bigr);
1248	    mpr_setd(bigr, numerator);
1249	    real.type = N_BIGRATIO;
1250	    real.data.bigratio = bigr;
1251	    rbr_canonicalize(&real);
1252	    number = make_real_object(&real);
1253	}
1254    }
1255    else {
1256	CHECK_REAL(number);
1257    }
1258
1259    return (number);
1260}
1261
1262LispObj *
1263Lisp_Rationalp(LispBuiltin *builtin)
1264/*
1265 rationalp object
1266 */
1267{
1268    LispObj *object;
1269
1270    object = ARGUMENT(0);
1271
1272    return (RATIONALP(object) ? T : NIL);
1273}
1274
1275LispObj *
1276Lisp_Realpart(LispBuiltin *builtin)
1277/*
1278 realpart number
1279 */
1280{
1281    LispObj *number;
1282
1283    number = ARGUMENT(0);
1284
1285    if (COMPLEXP(number))
1286	return (OCXR(number));
1287    else {
1288	CHECK_REAL(number);
1289    }
1290
1291    return (number);
1292}
1293
1294LispObj *
1295Lisp_Rem(LispBuiltin *builtin)
1296/*
1297 rem number divisor
1298 */
1299{
1300    LispObj *result;
1301
1302    LispObj *number, *divisor;
1303
1304    divisor = ARGUMENT(1);
1305    number = ARGUMENT(0);
1306
1307    if (INTEGERP(number) && INTEGERP(divisor)) {
1308	n_real real;
1309
1310	set_real_object(&real, number);
1311	rem_real_object(&real, divisor);
1312	result = make_real_object(&real);
1313    }
1314    else {
1315	n_number num;
1316
1317	set_number_object(&num, number);
1318	divide_number_object(&num, divisor, NDIVIDE_TRUNC, 0);
1319	result = make_real_object(&(num.imag));
1320	clear_real(&(num.real));
1321    }
1322
1323    return (result);
1324}
1325
1326LispObj *
1327Lisp_Sqrt(LispBuiltin *builtin)
1328/*
1329 sqrt number
1330 */
1331{
1332    n_number num;
1333    LispObj *number;
1334
1335    number = ARGUMENT(0);
1336
1337    set_number_object(&num, number);
1338    sqrt_number(&num);
1339
1340    return (make_number_object(&num));
1341}
1342
1343LispObj *
1344Lisp_Zerop(LispBuiltin *builtin)
1345/*
1346 zerop number
1347 */
1348{
1349    LispObj *result, *number;
1350
1351    number = ARGUMENT(0);
1352
1353    switch (OBJECT_TYPE(number)) {
1354	case LispFixnum_t:
1355	case LispInteger_t:
1356	case LispBignum_t:
1357	case LispDFloat_t:
1358	case LispRatio_t:
1359	case LispBigratio_t:
1360	    result = cmp_real_object(&zero, number) == 0 ? T : NIL;
1361	    break;
1362	case LispComplex_t:
1363	    result = cmp_real_object(&zero, OCXR(number)) == 0 &&
1364		     cmp_real_object(&zero, OCXI(number)) == 0 ? T : NIL;
1365	    break;
1366	default:
1367	    fatal_builtin_object_error(builtin, number, NOT_A_NUMBER);
1368	    /*NOTREACHED*/
1369	    result = NIL;
1370    }
1371
1372    return (result);
1373}
1374
1375static LispObj *
1376LispDivide(LispBuiltin *builtin, int fun, int flo)
1377{
1378    n_number num;
1379    LispObj *number, *divisor;
1380
1381    divisor = ARGUMENT(1);
1382    number = ARGUMENT(0);
1383
1384    RETURN_COUNT = 1;
1385
1386    if (cmp_real_object(&zero, number) == 0) {
1387	if (divisor != NIL) {
1388	    CHECK_REAL(divisor);
1389	}
1390
1391	return (RETURN(0) = obj_zero);
1392    }
1393
1394    if (divisor == UNSPEC)
1395	divisor = obj_one;
1396
1397    set_number_object(&num, number);
1398    if (num.complex)
1399	fatal_builtin_object_error(builtin, divisor, NOT_A_REAL_NUMBER);
1400
1401    divide_number_object(&num, divisor, fun, flo);
1402    RETURN(0) = make_real_object(&(num.imag));
1403
1404    return (make_real_object(&(num.real)));
1405}
1406
1407LispObj *
1408Lisp_Ceiling(LispBuiltin *builtin)
1409/*
1410 ceiling number &optional divisor
1411 */
1412{
1413    return (LispDivide(builtin, NDIVIDE_CEIL, 0));
1414}
1415
1416LispObj *
1417Lisp_Fceiling(LispBuiltin *builtin)
1418/*
1419 fceiling number &optional divisor
1420 */
1421{
1422    return (LispDivide(builtin, NDIVIDE_CEIL, 1));
1423}
1424
1425LispObj *
1426Lisp_Floor(LispBuiltin *builtin)
1427/*
1428 floor number &optional divisor
1429 */
1430{
1431    return (LispDivide(builtin, NDIVIDE_FLOOR, 0));
1432}
1433
1434LispObj *
1435Lisp_Ffloor(LispBuiltin *builtin)
1436/*
1437 ffloor number &optional divisor
1438 */
1439{
1440    return (LispDivide(builtin, NDIVIDE_FLOOR, 1));
1441}
1442
1443LispObj *
1444Lisp_Round(LispBuiltin *builtin)
1445/*
1446 round number &optional divisor
1447 */
1448{
1449    return (LispDivide(builtin, NDIVIDE_ROUND, 0));
1450}
1451
1452LispObj *
1453Lisp_Fround(LispBuiltin *builtin)
1454/*
1455 fround number &optional divisor
1456 */
1457{
1458    return (LispDivide(builtin, NDIVIDE_ROUND, 1));
1459}
1460
1461LispObj *
1462Lisp_Truncate(LispBuiltin *builtin)
1463/*
1464 truncate number &optional divisor
1465 */
1466{
1467    return (LispDivide(builtin, NDIVIDE_TRUNC, 0));
1468}
1469
1470LispObj *
1471Lisp_Ftruncate(LispBuiltin *builtin)
1472/*
1473 ftruncate number &optional divisor
1474 */
1475{
1476    return (LispDivide(builtin, NDIVIDE_TRUNC, 1));
1477}
1478