Mercurial > hg > xemacs-beta
changeset 1983:9c872f33ecbe
[xemacs-hg @ 2004-04-05 22:49:31 by james]
Add bignum, ratio, and bigfloat support.
author | james |
---|---|
date | Mon, 05 Apr 2004 22:50:11 +0000 |
parents | a748951fd4fb |
children | 36760cdcb631 |
files | lisp/ChangeLog lisp/cl-extra.el lisp/cl.el src/ChangeLog src/Makefile.in.in src/alloc.c src/bytecode.c src/config.h.in src/data.c src/depend src/doprnt.c src/emacs.c src/floatfns.c src/fns.c src/general-slots.h src/lisp.h src/lread.c src/lrecord.h src/number-gmp.c src/number-gmp.h src/number-mp.c src/number-mp.h src/number.c src/number.h src/symsinit.h src/sysdep.c tests/ChangeLog tests/automated/lisp-tests.el |
diffstat | 28 files changed, 4349 insertions(+), 59 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Mon Apr 05 21:50:47 2004 +0000 +++ b/lisp/ChangeLog Mon Apr 05 22:50:11 2004 +0000 @@ -1,3 +1,12 @@ +2004-04-05 Jerry James <james@xemacs.org> + + * cl-extra.el (coerce): Add support for general numeric conversions. + * cl.el (eql): Update for more number types. + * cl.el (cl-random-time): Ensure the result is a fixnum. + * cl.el (most-positive-fixnum): Do not define in Lisp if enhanced + number types are available. + * cl.el (most-negative-fixnum): Ditto. + 2004-03-23 Adrian Aichner <adrian@xemacs.org> * code-process.el (call-process-region): Correct start and end
--- a/lisp/cl-extra.el Mon Apr 05 21:50:47 2004 +0000 +++ b/lisp/cl-extra.el Mon Apr 05 22:50:11 2004 +0000 @@ -80,6 +80,9 @@ ((and (eq type 'character) (char-int-p x)) (int-char x)) ((and (eq type 'integer) (characterp x)) (char-int x)) ((eq type 'float) (float x)) + ((and (featurep 'number-types) + (memq type '(integer ratio bigfloat)) + (coerce-number x type))) ((eq type 'bit-vector) (if (bit-vector-p x) x (apply 'bit-vector (append x nil)))) ((eq type 'weak-list)
--- a/lisp/cl.el Mon Apr 05 21:50:47 2004 +0000 +++ b/lisp/cl.el Mon Apr 05 22:50:11 2004 +0000 @@ -151,10 +151,8 @@ (defun eql (a b) ; See compiler macro in cl-macs.el "Return t if the two args are the same Lisp object. Floating-point numbers of equal value are `eql', but they may not be `eq'." - (if (floatp a) - (equal a b) - (eq a b))) - + (or (eq a b) + (and (numberp a) (numberp b) (equal a b)))) ;;; Generalized variables. These macros are defined here so that they ;;; can safely be used in .emacs files. @@ -313,7 +311,9 @@ (defun cl-random-time () (let* ((time (copy-sequence (current-time-string))) (i (length time)) (v 0)) (while (>= (decf i) 0) (setq v (+ (* v 3) (aref time i)))) - v)) + (if (featurep 'number-types) + (coerce-number v 'fixnum) + v))) (defvar *gensym-counter* (* (logand (cl-random-time) 1023) 100)) @@ -364,11 +364,13 @@ (defvar *random-state* (vector 'cl-random-state-tag -1 30 (cl-random-time))) +;; These constants are defined in C when 'number-types is provided. +(unless (featurep 'number-types) ;;; We use `eval' in case VALBITS differs from compile-time to load-time. -(defconst most-positive-fixnum (eval '(lsh -1 -1)) - "The integer closest in value to positive infinity.") -(defconst most-negative-fixnum (eval '(- -1 (lsh -1 -1))) - "The integer closest in value to negative infinity.") + (defconst most-positive-fixnum (eval '(lsh -1 -1)) + "The integer closest in value to positive infinity.") + (defconst most-negative-fixnum (eval '(- -1 (lsh -1 -1))) + "The integer closest in value to negative infinity.")) ;;; The following are set by code in cl-extra.el (defconst most-positive-float nil
--- a/src/ChangeLog Mon Apr 05 21:50:47 2004 +0000 +++ b/src/ChangeLog Mon Apr 05 22:50:11 2004 +0000 @@ -1,3 +1,89 @@ +2004-04-05 Jerry James <james@xemacs.org> + + * Makefile.in.in (number_objs): New. + * Makefile.in.in (objs): Use it. + * alloc.c: Make comment more precise. + * alloc.c (make_bignum): New function. + * alloc.c (make_bignum_bg): New function. + * alloc.c (make_ratio): New function. + * alloc.c (make_ratio_bg): New function. + * alloc.c (make_ratio_rt): New function. + * alloc.c (make_bigfloat): New function. + * alloc.c (make_bigfloat_bf): New function. + * alloc.c (sweep_bignums): New function. + * alloc.c (sweep_ratios): New function. + * alloc.c (sweep_bigfloats): New function. + * alloc.c (gc_sweep): Use the new sweep functions. + * alloc.c (Fgarbage_collect): Report collected number objects. + * alloc.c (common_init_alloc_early): Initialize number allocators. + * bytecode.c (bytecode_negate): Negate more number types. + * bytecode.c (bytecode_arithcompare): Compare more number types. + * bytecode.c (bytecode_arithop): Operate on more number types. + * bytecode.c (execute_optimized_program): Several changes in + support of the new number types. + * config.h.in: Add SIZEOF_DOUBLE, DOUBLE_BITS, WITH_NUMBER_TYPES, + WITH_GMP, WITH_MP, MP_PREFIX, and HAVE_MP_MOVE. + * data.c: Add symbol Qnonnegativep. + * data.c (Ffixnump): New function. + * data.c (Fnatnump): Work with bignums alos. + * data.c (Fnonnegativep): New function. + * data.c (Fnumberp): Return t for any number type. + * data.c (ARITHCOMPARE_MANY): Add cases for the new number types. + * data.c (Feqlsign): Work with the new number types. + * data.c (Flss): Ditto. + * data.c (Fgtr): Ditto. + * data.c (Fleq): Ditto. + * data.c (Fgeq): Ditto. + * data.c (Fneq): Ditto. + * data.c (Fzerop): Ditto. + * data.c (Fnumber_to_string): Ditto. + * data.c (Fstring_to_number): Ditto. + * data.c (Fplus): Ditto. + * data.c (Fminus): Ditto. + * data.c (Ftimes): Ditto. + * data.c (Fdiv): New function to produce ratios. + * data.c (Fquo): Work with the new number types. + * data.c (Fmax): Ditto. + * data.c (Fmin): Ditto. + * data.c (Flogand): Ditto. + * data.c (Flogior): Ditto. + * data.c (Flogxor): Ditto. + * data.c (Flognot): Ditto. + * data.c (Frem): Ditto. + * data.c (Fmod): Ditto. + * data.c (Fash): Ditto. + * data.c (Flsh): Ditto. + * data.c (Fadd1): Ditto. + * data.c (Fsub1): Ditto. + * data.c (syms_of_data): Declare new symbols and Lisp functions. + * depend: Regenerate. + * doprnt.c: Add converters for the new number types. + * doprnt.c (union printf_arg): Add new obj field. + * doprnt.c (get_doprnt_args): Use the new converters. + * doprnt.c (emacs_doprnt_1): Convert and print the new number types. + * emacs.c (main_1): Call syms_of_, vars_of_, and init_number. + * floatfns.c (float_to_int): Convert to bignums if necessary. + * floatfns.c (extract_float): Extract the new number types. + * floatfns.c (Fexpt): Work with bignums. + * floatfns.c (Fsqrt): Ditto. + * floatfns.c (Fabs): Work with the new number types. + * floatfns.c (Ffloat): Ditto. + * floatfns.c (Fceiling): Ditto. + * floatfns.c (Ffloor): Ditto. + * floatfns.c (Fround): Ditto. + * floatfns.c (Ftruncate): Ditto. + * fns.c (Frandom): Update docstring and accept bignum limits. + * fns.c (internal_equalp): Work with the new number types. + * general-slots.h: Add new type name symbols. + * lisp.h: Include number.h. Add isratio_string prototype. + Declare Qnonnegativep and Qnumberp. + * lread.c (read_atom): Read ratios. + * lread.c (parse_integer): Read bignums. + * lread.c (isratio_string): New functions. + * lrecord.h (lrecord_type): Add new number type values. + * symsinit.h: Declare syms_of_, vars_of_, and init_number. + * sysdep.c (seed_random): Set the bignum random seed. + 2004-03-30 Zajcev Evgeny <zevlg@yandex.ru> * window.c: Declare `allow_deletion_of_last_visible_frame' extern.
--- a/src/Makefile.in.in Mon Apr 05 21:50:47 2004 +0000 +++ b/src/Makefile.in.in Mon Apr 05 22:50:11 2004 +0000 @@ -204,6 +204,13 @@ mule_wnn_objs=mule-wnnfns.o #endif +#ifdef WITH_GMP +number_objs=number-gmp.o number.o +#endif +#ifdef WITH_MP +number_objs=number-mp.o number.o +#endif + #if defined(HAVE_POSTGRESQL) && !defined(HAVE_SHLIB) postgresql_objs=$(BLDMODULES)/postgresql/postgresql.o #endif @@ -268,8 +275,8 @@ hash.o imgproc.o indent.o insdel.o intl.o\ keymap.o $(RTC_patch_objs) line-number.o $(ldap_objs) lread.o lstream.o\ macros.o marker.o md5.o minibuf.o $(mswindows_objs) $(mswindows_gui_objs)\ - $(mule_objs) $(mule_canna_objs) $(mule_wnn_objs) objects.o opaque.o\ - $(postgresql_objs) print.o process.o $(process_objs) $(profile_objs)\ + $(mule_objs) $(mule_canna_objs) $(mule_wnn_objs) $(number_objs) objects.o\ + opaque.o $(postgresql_objs) print.o process.o $(process_objs) $(profile_objs)\ rangetab.o realpath.o redisplay.o redisplay-output.o regex.o\ search.o select.o $(sheap_objs) $(shlib_objs) signal.o sound.o\ specifier.o strftime.o $(sunpro_objs) symbols.o syntax.o sysdep.o\
--- a/src/alloc.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/alloc.c Mon Apr 05 22:50:11 2004 +0000 @@ -645,8 +645,8 @@ may be more efficient when there are only a small number of them. The types that are stored in these large blocks (or "frob blocks") - are cons, float, compiled-function, symbol, marker, extent, event, - and string. + are cons, all number types except fixnum, compiled-function, symbol, + marker, extent, event, and string. Note that strings are special in that they are actually stored in two parts: a structure containing information about the string, and @@ -1163,6 +1163,8 @@ /* Float allocation */ /************************************************************************/ +/*** With enhanced number support, these are short floats */ + DECLARE_FIXED_TYPE_ALLOC (float, Lisp_Float); #define MINIMUM_ALLOWED_FIXED_TYPE_CELLS_float 1000 @@ -1184,6 +1186,124 @@ /************************************************************************/ +/* Enhanced number allocation */ +/************************************************************************/ + +/*** Bignum ***/ +#ifdef HAVE_BIGNUM +DECLARE_FIXED_TYPE_ALLOC (bignum, Lisp_Bignum); +#define MINIMUM_ALLOWED_FIXED_TYPE_CELLS_bignum 250 + +/* WARNING: This function returns a bignum even if its argument fits into a + fixnum. See Fcanonicalize_number(). */ +Lisp_Object +make_bignum (long bignum_value) +{ + Lisp_Bignum *b; + + ALLOCATE_FIXED_TYPE (bignum, Lisp_Bignum, b); + set_lheader_implementation (&b->lheader, &lrecord_bignum); + bignum_init (bignum_data (b)); + bignum_set_long (bignum_data (b), bignum_value); + return wrap_bignum (b); +} + +/* WARNING: This function returns a bignum even if its argument fits into a + fixnum. See Fcanonicalize_number(). */ +Lisp_Object +make_bignum_bg (bignum bg) +{ + Lisp_Bignum *b; + + ALLOCATE_FIXED_TYPE (bignum, Lisp_Bignum, b); + set_lheader_implementation (&b->lheader, &lrecord_bignum); + bignum_init (bignum_data (b)); + bignum_set (bignum_data (b), bg); + return wrap_bignum (b); +} +#endif /* HAVE_BIGNUM */ + +/*** Ratio ***/ +#ifdef HAVE_RATIO +DECLARE_FIXED_TYPE_ALLOC (ratio, Lisp_Ratio); +#define MINIMUM_ALLOWED_FIXED_TYPE_CELLS_ratio 250 + +Lisp_Object +make_ratio (long numerator, unsigned long denominator) +{ + Lisp_Ratio *r; + + ALLOCATE_FIXED_TYPE (ratio, Lisp_Ratio, r); + set_lheader_implementation (&r->lheader, &lrecord_ratio); + ratio_init (ratio_data (r)); + ratio_set_long_ulong (ratio_data (r), numerator, denominator); + ratio_canonicalize (ratio_data (r)); + return wrap_ratio (r); +} + +Lisp_Object +make_ratio_bg (bignum numerator, bignum denominator) +{ + Lisp_Ratio *r; + + ALLOCATE_FIXED_TYPE (ratio, Lisp_Ratio, r); + set_lheader_implementation (&r->lheader, &lrecord_ratio); + ratio_init (ratio_data (r)); + ratio_set_bignum_bignum (ratio_data (r), numerator, denominator); + ratio_canonicalize (ratio_data (r)); + return wrap_ratio (r); +} + +Lisp_Object +make_ratio_rt (ratio rat) +{ + Lisp_Ratio *r; + + ALLOCATE_FIXED_TYPE (ratio, Lisp_Ratio, r); + set_lheader_implementation (&r->lheader, &lrecord_ratio); + ratio_init (ratio_data (r)); + ratio_set (ratio_data (r), rat); + return wrap_ratio (r); +} +#endif /* HAVE_RATIO */ + +/*** Bigfloat ***/ +#ifdef HAVE_BIGFLOAT +DECLARE_FIXED_TYPE_ALLOC (bigfloat, Lisp_Bigfloat); +#define MINIMUM_ALLOWED_FIXED_TYPE_CELLS_bigfloat 250 + +/* This function creates a bigfloat with the default precision if the + PRECISION argument is zero. */ +Lisp_Object +make_bigfloat (double float_value, unsigned long precision) +{ + Lisp_Bigfloat *f; + + ALLOCATE_FIXED_TYPE (bigfloat, Lisp_Bigfloat, f); + set_lheader_implementation (&f->lheader, &lrecord_bigfloat); + if (precision == 0UL) + bigfloat_init (bigfloat_data (f)); + else + bigfloat_init_prec (bigfloat_data (f), precision); + bigfloat_set_double (bigfloat_data (f), float_value); + return wrap_bigfloat (f); +} + +/* This function creates a bigfloat with the precision of its argument */ +Lisp_Object +make_bigfloat_bf (bigfloat float_value) +{ + Lisp_Bigfloat *f; + + ALLOCATE_FIXED_TYPE (bigfloat, Lisp_Bigfloat, f); + set_lheader_implementation (&f->lheader, &lrecord_bigfloat); + bigfloat_init_prec (bigfloat_data (f), bigfloat_get_prec (float_value)); + bigfloat_set (bigfloat_data (f), float_value); + return wrap_bigfloat (f); +} +#endif /* HAVE_BIGFLOAT */ + +/************************************************************************/ /* Vector allocation */ /************************************************************************/ @@ -3786,6 +3906,39 @@ SWEEP_FIXED_TYPE_BLOCK (float, Lisp_Float); } +#ifdef HAVE_BIGNUM +static void +sweep_bignums (void) +{ +#define UNMARK_bignum(ptr) UNMARK_RECORD_HEADER (&((ptr)->lheader)) +#define ADDITIONAL_FREE_bignum(ptr) bignum_fini (ptr->data) + + SWEEP_FIXED_TYPE_BLOCK (bignum, Lisp_Bignum); +} +#endif /* HAVE_BIGNUM */ + +#ifdef HAVE_RATIO +static void +sweep_ratios (void) +{ +#define UNMARK_ratio(ptr) UNMARK_RECORD_HEADER (&((ptr)->lheader)) +#define ADDITIONAL_FREE_ratio(ptr) ratio_fini (ptr->data) + + SWEEP_FIXED_TYPE_BLOCK (ratio, Lisp_Ratio); +} +#endif /* HAVE_RATIO */ + +#ifdef HAVE_BIGFLOAT +static void +sweep_bigfloats (void) +{ +#define UNMARK_bigfloat(ptr) UNMARK_RECORD_HEADER (&((ptr)->lheader)) +#define ADDITIONAL_FREE_bigfloat(ptr) bigfloat_fini (ptr->bf) + + SWEEP_FIXED_TYPE_BLOCK (bigfloat, Lisp_Bigfloat); +} +#endif + static void sweep_symbols (void) { @@ -4237,6 +4390,21 @@ /* Put all unmarked floats on free list */ sweep_floats (); +#ifdef HAVE_BIGNUM + /* Put all unmarked bignums on free list */ + sweep_bignums (); +#endif + +#ifdef HAVE_RATIO + /* Put all unmarked ratios on free list */ + sweep_ratios (); +#endif + +#ifdef HAVE_BIGFLOAT + /* Put all unmarked bigfloats on free list */ + sweep_bigfloats (); +#endif + /* Put all unmarked symbols on free list */ sweep_symbols (); @@ -4796,6 +4964,21 @@ HACK_O_MATIC (float, "float-storage", pl); pl = gc_plist_hack ("floats-free", gc_count_num_float_freelist, pl); pl = gc_plist_hack ("floats-used", gc_count_num_float_in_use, pl); +#ifdef HAVE_BIGNUM + HACK_O_MATIC (bignum, "bignum-storage", pl); + pl = gc_plist_hack ("bignums-free", gc_count_num_bignum_freelist, pl); + pl = gc_plist_hack ("bignums-used", gc_count_num_bignum_in_use, pl); +#endif /* HAVE_BIGNUM */ +#ifdef HAVE_RATIO + HACK_O_MATIC (ratio, "ratio-storage", pl); + pl = gc_plist_hack ("ratios-free", gc_count_num_ratio_freelist, pl); + pl = gc_plist_hack ("ratios-used", gc_count_num_ratio_in_use, pl); +#endif /* HAVE_RATIO */ +#ifdef HAVE_BIGFLOAT + HACK_O_MATIC (bigfloat, "bigfloat-storage", pl); + pl = gc_plist_hack ("bigfloats-free", gc_count_num_bigfloat_freelist, pl); + pl = gc_plist_hack ("bigfloats-used", gc_count_num_bigfloat_in_use, pl); +#endif /* HAVE_BIGFLOAT */ HACK_O_MATIC (string, "string-header-storage", pl); pl = gc_plist_hack ("long-strings-total-length", gc_count_string_total_size @@ -5079,6 +5262,15 @@ init_symbol_alloc (); init_compiled_function_alloc (); init_float_alloc (); +#ifdef HAVE_BIGNUM + init_bignum_alloc (); +#endif +#ifdef HAVE_RATIO + init_ratio_alloc (); +#endif +#ifdef HAVE_BIGFLOAT + init_bigfloat_alloc (); +#endif init_marker_alloc (); init_extent_alloc (); init_event_alloc ();
--- a/src/bytecode.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/bytecode.c Mon Apr 05 22:50:11 2004 +0000 @@ -246,10 +246,19 @@ { retry: - if (INTP (obj)) return make_int (- XINT (obj)); + if (INTP (obj)) return make_integer (- XINT (obj)); if (FLOATP (obj)) return make_float (- XFLOAT_DATA (obj)); - if (CHARP (obj)) return make_int (- ((int) XCHAR (obj))); - if (MARKERP (obj)) return make_int (- ((int) marker_position (obj))); + if (CHARP (obj)) return make_integer (- ((int) XCHAR (obj))); + if (MARKERP (obj)) return make_integer (- ((int) marker_position (obj))); +#ifdef HAVE_BIGNUM + if (BIGNUMP (obj)) BIGNUM_ARITH_RETURN (obj, neg); +#endif +#ifdef HAVE_RATIO + if (RATIOP (obj)) RATIO_ARITH_RETURN (obj, neg); +#endif +#ifdef HAVE_BIG_FLOAT + if (BIGFLOAT_P (obj)) BIGFLOAT_ARITH_RETURN (obj, neg); +#endif obj = wrong_type_argument (Qnumber_char_or_marker_p, obj); goto retry; @@ -279,6 +288,33 @@ static int bytecode_arithcompare (Lisp_Object obj1, Lisp_Object obj2) { +#ifdef WITH_NUMBER_TYPES + switch (promote_args (&obj1, &obj2)) + { + case FIXNUM_T: + { + EMACS_INT ival1 = XREALINT (obj1), ival2 = XREALINT (obj2); + return ival1 < ival2 ? -1 : ival1 > ival2 ? 1 : 0; + } +#ifdef HAVE_BIGNUM + case BIGNUM_T: + return bignum_cmp (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2)); +#endif +#ifdef HAVE_RATIO + case RATIO_T: + return ratio_cmp (XRATIO_DATA (obj1), XRATIO_DATA (obj2)); +#endif + case FLOAT_T: + { + double dval1 = XFLOAT_DATA (obj1), dval2 = XFLOAT_DATA (obj2); + return dval1 < dval2 ? -1 : dval1 > dval2 ? 1 : 0; + } +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + return bigfloat_cmp (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2)); +#endif + } +#else /* !WITH_NUMBER_TYPES */ retry: { @@ -324,11 +360,151 @@ return dval1 < dval2 ? -1 : dval1 > dval2 ? 1 : 0; } +#endif /* WITH_NUMBER_TYPES */ } static Lisp_Object bytecode_arithop (Lisp_Object obj1, Lisp_Object obj2, Opcode opcode) { +#ifdef WITH_NUMBER_TYPES + switch (promote_args (&obj1, &obj2)) + { + case FIXNUM_T: + { + EMACS_INT ival1 = XREALINT (obj1), ival2 = XREALINT (obj2); + switch (opcode) + { + case Bplus: ival1 += ival2; break; + case Bdiff: ival1 -= ival2; break; + case Bmult: +#ifdef HAVE_BIGNUM + /* Due to potential overflow, we compute using bignums */ + bignum_set_long (scratch_bignum, ival1); + bignum_set_long (scratch_bignum2, ival2); + bignum_mul (scratch_bignum, scratch_bignum, scratch_bignum2); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#else + ival1 *= ival2; break; +#endif + case Bquo: + if (ival2 == 0) Fsignal (Qarith_error, Qnil); + ival1 /= ival2; + break; + case Bmax: if (ival1 < ival2) ival1 = ival2; break; + case Bmin: if (ival1 > ival2) ival1 = ival2; break; + } + return make_integer (ival1); + } +#ifdef HAVE_BIGNUM + case BIGNUM_T: + switch (opcode) + { + case Bplus: + bignum_add (scratch_bignum, XBIGNUM_DATA (obj1), + XBIGNUM_DATA (obj2)); + break; + case Bdiff: + bignum_sub (scratch_bignum, XBIGNUM_DATA (obj1), + XBIGNUM_DATA (obj2)); + break; + case Bmult: + bignum_mul (scratch_bignum, XBIGNUM_DATA (obj1), + XBIGNUM_DATA (obj2)); + break; + case Bquo: + if (bignum_sign (XBIGNUM_DATA (obj2)) == 0) + Fsignal (Qarith_error, Qnil); + bignum_div (scratch_bignum, XBIGNUM_DATA (obj1), + XBIGNUM_DATA (obj2)); + break; + case Bmax: + return bignum_gt (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2)) + ? obj1 : obj2; + case Bmin: + return bignum_lt (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2)) + ? obj1 : obj2; + } + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#endif +#ifdef HAVE_RATIO + case RATIO_T: + switch (opcode) + { + case Bplus: + ratio_add (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2)); + break; + case Bdiff: + ratio_sub (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2)); + break; + case Bmult: + ratio_mul (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2)); + break; + case Bquo: + if (ratio_sign (XRATIO_DATA (obj2)) == 0) + Fsignal (Qarith_error, Qnil); + ratio_div (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2)); + break; + case Bmax: + return ratio_gt (XRATIO_DATA (obj1), XRATIO_DATA (obj2)) + ? obj1 : obj2; + case Bmin: + return ratio_lt (XRATIO_DATA (obj1), XRATIO_DATA (obj2)) + ? obj1 : obj2; + } + return make_ratio_rt (scratch_ratio); +#endif + case FLOAT_T: + { + double dval1 = XFLOAT_DATA (obj1), dval2 = XFLOAT_DATA (obj2); + switch (opcode) + { + case Bplus: dval1 += dval2; break; + case Bdiff: dval1 -= dval2; break; + case Bmult: dval1 *= dval2; break; + case Bquo: + if (dval2 == 0.0) Fsignal (Qarith_error, Qnil); + dval1 /= dval2; + break; + case Bmax: if (dval1 < dval2) dval1 = dval2; break; + case Bmin: if (dval1 > dval2) dval1 = dval2; break; + } + return make_float (dval1); + } +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + bigfloat_set_prec (scratch_bigfloat, max (XBIGFLOAT_GET_PREC (obj1), + XBIGFLOAT_GET_PREC (obj2))); + switch (opcode) + { + case Bplus: + bigfloat_add (scratch_bigfloat, XBIGFLOAT_DATA (obj1), + XBIGFLOAT_DATA (obj2)); + break; + case Bdiff: + bigfloat_sub (scratch_bigfloat, XBIGFLOAT_DATA (obj1), + XBIGFLOAT_DATA (obj2)); + break; + case Bmult: + bigfloat_mul (scratch_bigfloat, XBIGFLOAT_DATA (obj1), + XBIGFLOAT_DATA (obj2)); + break; + case Bquo: + if (bigfloat_sign (XBIGFLOAT_DATA (obj2)) == 0) + Fsignal (Qarith_error, Qnil); + bigfloat_div (scratch_bigfloat, XBIGFLOAT_DATA (obj1), + XBIGFLOAT_DATA (obj2)); + break; + case Bmax: + return bigfloat_gt (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2)) + ? obj1 : obj2; + case Bmin: + return bigfloat_lt (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2)) + ? obj1 : obj2; + } + return make_bigfloat_bf (scratch_bigfloat); +#endif + } +#else /* !WITH_NUMBER_TYPES */ EMACS_INT ival1, ival2; int float_p; @@ -390,6 +566,7 @@ } return make_float (dval1); } +#endif /* WITH_NUMBER_TYPES */ } @@ -806,11 +983,19 @@ break; case Bnumberp: +#ifdef WITH_NUMBER_TYPES + TOP = NUMBERP (TOP) ? Qt : Qnil; +#else TOP = INT_OR_FLOATP (TOP) ? Qt : Qnil; +#endif break; case Bintegerp: +#ifdef HAVE_BIGNUM + TOP = INTEGERP (TOP) ? Qt : Qnil; +#else TOP = INTP (TOP) ? Qt : Qnil; +#endif break; case Beq: @@ -907,11 +1092,19 @@ } case Bsub1: +#ifdef HAVE_BIGNUM + TOP = Fsub1 (TOP); +#else TOP = INTP (TOP) ? INT_MINUS1 (TOP) : Fsub1 (TOP); +#endif break; case Badd1: +#ifdef HAVE_BIGNUM + TOP = Fadd1 (TOP); +#else TOP = INTP (TOP) ? INT_PLUS1 (TOP) : Fadd1 (TOP); +#endif break; @@ -966,9 +1159,13 @@ { Lisp_Object arg2 = POP; Lisp_Object arg1 = TOP; +#ifdef HAVE_BIGNUM + TOP = bytecode_arithop (arg1, arg2, opcode); +#else TOP = INTP (arg1) && INTP (arg2) ? INT_PLUS (arg1, arg2) : bytecode_arithop (arg1, arg2, opcode); +#endif break; } @@ -976,9 +1173,13 @@ { Lisp_Object arg2 = POP; Lisp_Object arg1 = TOP; +#ifdef HAVE_BIGNUM + TOP = bytecode_arithop (arg1, arg2, opcode); +#else TOP = INTP (arg1) && INTP (arg2) ? INT_MINUS (arg1, arg2) : bytecode_arithop (arg1, arg2, opcode); +#endif break; }
--- a/src/config.h.in Mon Apr 05 21:50:47 2004 +0000 +++ b/src/config.h.in Mon Apr 05 22:50:11 2004 +0000 @@ -893,6 +893,7 @@ #undef SIZEOF_LONG #undef SIZEOF_LONG_LONG #undef SIZEOF_VOID_P +#undef SIZEOF_DOUBLE /* some systems (Cygwin) typedef u?intptr_t in <sys/types.h> but the standard is <inttypes.h> @@ -912,6 +913,14 @@ #define LONGBITS (SIZEOF_LONG * BITS_PER_CHAR) #define LONG_LONG_BITS (SIZEOF_LONG_LONG * BITS_PER_CHAR) #define VOID_P_BITS (SIZEOF_VOID_P * BITS_PER_CHAR) +#define DOUBLE_BITS (SIZEOF_DOUBLE * BITS_PER_CHAR) + +/* Enhanced numeric support */ +#undef WITH_NUMBER_TYPES +#undef WITH_GMP +#undef WITH_MP +#undef MP_PREFIX +#undef HAVE_MP_MOVE /* Use `INLINE_HEADER' to define inline functions in .h files. Use `inline static' to define inline functions in .c files.
--- a/src/data.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/data.c Mon Apr 05 22:50:11 2004 +0000 @@ -53,7 +53,7 @@ Lisp_Object Qtext_conversion_error; Lisp_Object Qarith_error, Qrange_error, Qdomain_error; Lisp_Object Qsingularity_error, Qoverflow_error, Qunderflow_error; -Lisp_Object Qintegerp, Qnatnump, Qsymbolp; +Lisp_Object Qintegerp, Qnatnump, Qnonnegativep, Qsymbolp; Lisp_Object Qlistp, Qtrue_list_p, Qweak_listp; Lisp_Object Qconsp, Qsubrp; Lisp_Object Qcharacterp, Qstringp, Qarrayp, Qsequencep, Qvectorp; @@ -460,6 +460,16 @@ return CHAR_OR_CHAR_INTP (object) || STRINGP (object) ? Qt : Qnil; } +#ifdef HAVE_BIGNUM +/* In this case, integerp is defined in number.c. */ +DEFUN ("fixnump", Ffixnump, 1, 1, 0, /* +Return t if OBJECT is a fixnum. +*/ + (object)) +{ + return INTP (object) ? Qt : Qnil; +} +#else DEFUN ("integerp", Fintegerp, 1, 1, 0, /* Return t if OBJECT is an integer. */ @@ -467,6 +477,7 @@ { return INTP (object) ? Qt : Qnil; } +#endif DEFUN ("integer-or-marker-p", Finteger_or_marker_p, 1, 1, 0, /* Return t if OBJECT is an integer or a marker (editor pointer). @@ -497,7 +508,29 @@ */ (object)) { - return NATNUMP (object) ? Qt : Qnil; + return NATNUMP (object) +#ifdef HAVE_BIGNUM + || (BIGNUMP (object) && bignum_sign (XBIGNUM_DATA (object)) >= 0) +#endif + ? Qt : Qnil; +} + +DEFUN ("nonnegativep", Fnonnegativep, 1, 1, 0, /* +Return t if OBJECT is a nonnegative number. +*/ + (object)) +{ + return NATNUMP (object) +#ifdef HAVE_BIGNUM + || (BIGNUMP (object) && bignum_sign (XBIGNUM_DATA (object)) >= 0) +#endif +#ifdef HAVE_RATIO + || (RATIOP (object) && ratio_sign (XRATIO_DATA (object)) >= 0) +#endif +#ifdef HAVE_BIGFLOAT + || (BIGFLOATP (object) && bigfloat_sign (XBIGFLOAT_DATA (object)) >= 0) +#endif + ? Qt : Qnil; } DEFUN ("bitp", Fbitp, 1, 1, 0, /* @@ -513,7 +546,11 @@ */ (object)) { +#ifdef WITH_NUMBER_TYPES + return NUMBERP (object) ? Qt : Qnil; +#else return INT_OR_FLOATP (object) ? Qt : Qnil; +#endif } DEFUN ("number-or-marker-p", Fnumber_or_marker_p, 1, 1, 0, /* @@ -854,7 +891,66 @@ } } -#define ARITHCOMPARE_MANY(op) \ +#ifdef WITH_NUMBER_TYPES + +#ifdef HAVE_BIGNUM +#define BIGNUM_CASE(op) \ + case BIGNUM_T: \ + if (!bignum_##op (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2))) \ + return Qnil; \ + break; +#else +#define BIGNUM_CASE(op) +#endif /* HAVE_BIGNUM */ + +#ifdef HAVE_RATIO +#define RATIO_CASE(op) \ + case RATIO_T: \ + if (!ratio_##op (XRATIO_DATA (obj1), XRATIO_DATA (obj2))) \ + return Qnil; \ + break; +#else +#define RATIO_CASE(op) +#endif /* HAVE_RATIO */ + +#ifdef HAVE_BIGFLOAT +#define BIGFLOAT_CASE(op) \ + case BIGFLOAT_T: \ + if (!bigfloat_##op (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2))) \ + return Qnil; \ + break; +#else +#define BIGFLOAT_CASE(op) +#endif /* HAVE_BIGFLOAT */ + +#define ARITHCOMPARE_MANY(c_op,op) \ +{ \ + REGISTER int i; \ + Lisp_Object obj1, obj2; \ + \ + for (i = 1; i < nargs; i++) \ + { \ + obj1 = args[i - 1]; \ + obj2 = args[i]; \ + switch (promote_args (&obj1, &obj2)) \ + { \ + case FIXNUM_T: \ + if (!(XREALINT (obj1) c_op XREALINT (obj2))) \ + return Qnil; \ + break; \ + BIGNUM_CASE (op) \ + RATIO_CASE (op) \ + case FLOAT_T: \ + if (!(XFLOAT_DATA (obj1) c_op XFLOAT_DATA (obj2))) \ + return Qnil; \ + break; \ + BIGFLOAT_CASE (op) \ + } \ + } \ + return Qt; \ +} +#else /* !WITH_NUMBER_TYPES */ +#define ARITHCOMPARE_MANY(c_op,op) \ { \ int_or_double iod1, iod2, *p = &iod1, *q = &iod2; \ Lisp_Object *args_end = args + nargs; \ @@ -866,8 +962,8 @@ number_char_or_marker_to_int_or_double (*args++, q); \ \ if (!((p->int_p && q->int_p) ? \ - (p->c.ival op q->c.ival) : \ - ((p->int_p ? (double) p->c.ival : p->c.dval) op \ + (p->c.ival c_op q->c.ival) : \ + ((p->int_p ? (double) p->c.ival : p->c.dval) c_op \ (q->int_p ? (double) q->c.ival : q->c.dval)))) \ return Qnil; \ \ @@ -875,6 +971,7 @@ } \ return Qt; \ } +#endif /* WITH_NUMBER_TYPES */ DEFUN ("=", Feqlsign, 1, MANY, 0, /* Return t if all the arguments are numerically equal. @@ -882,7 +979,7 @@ */ (int nargs, Lisp_Object *args)) { - ARITHCOMPARE_MANY (==) + ARITHCOMPARE_MANY (==, eql) } DEFUN ("<", Flss, 1, MANY, 0, /* @@ -891,7 +988,7 @@ */ (int nargs, Lisp_Object *args)) { - ARITHCOMPARE_MANY (<) + ARITHCOMPARE_MANY (<, lt) } DEFUN (">", Fgtr, 1, MANY, 0, /* @@ -900,7 +997,7 @@ */ (int nargs, Lisp_Object *args)) { - ARITHCOMPARE_MANY (>) + ARITHCOMPARE_MANY (>, gt) } DEFUN ("<=", Fleq, 1, MANY, 0, /* @@ -909,7 +1006,7 @@ */ (int nargs, Lisp_Object *args)) { - ARITHCOMPARE_MANY (<=) + ARITHCOMPARE_MANY (<=, le) } DEFUN (">=", Fgeq, 1, MANY, 0, /* @@ -918,15 +1015,64 @@ */ (int nargs, Lisp_Object *args)) { - ARITHCOMPARE_MANY (>=) + ARITHCOMPARE_MANY (>=, ge) } +/* Unlike all the other comparisons, this is an O(N*N) algorithm. But who + cares? Inspection of all elisp code distributed by xemacs.org shows that + it is almost always called with 2 arguments, rarely with 3, and never with + more than 3. The constant factors of algorithms with better asymptotic + complexity are higher, which means that those algorithms will run SLOWER + than this one in the common case. Optimize the common case! */ DEFUN ("/=", Fneq, 1, MANY, 0, /* Return t if no two arguments are numerically equal. The arguments may be numbers, characters or markers. */ (int nargs, Lisp_Object *args)) { +#ifdef WITH_NUMBER_TYPES + REGISTER int i, j; + Lisp_Object obj1, obj2; + + for (i = 0; i < nargs - 1; i++) + { + obj1 = args[i]; + for (j = i + 1; j < nargs; j++) + { + obj2 = args[j]; + switch (promote_args (&obj1, &obj2)) + { + case FIXNUM_T: + if (XREALINT (obj1) == XREALINT (obj2)) + return Qnil; + break; +#ifdef HAVE_BIGNUM + case BIGNUM_T: + if (bignum_eql (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2))) + return Qnil; + break; +#endif +#ifdef HAVE_RATIO + case RATIO_T: + if (ratio_eql (XRATIO_DATA (obj1), XRATIO_DATA (obj2))) + return Qnil; + break; +#endif + case FLOAT_T: + if (XFLOAT_DATA (obj1) == XFLOAT_DATA (obj2)) + return Qnil; + break; +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + if (bigfloat_eql (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2))) + return Qnil; + break; +#endif + } + } + } + return Qt; +#else /* !WITH_NUMBER_TYPES */ Lisp_Object *args_end = args + nargs; Lisp_Object *p, *q; @@ -949,6 +1095,7 @@ } } return Qt; +#endif /* WITH_NUMBER_TYPES */ } DEFUN ("zerop", Fzerop, 1, 1, 0, /* @@ -959,8 +1106,20 @@ retry: if (INTP (number)) return EQ (number, Qzero) ? Qt : Qnil; +#ifdef HAVE_BIGNUM + else if (BIGNUMP (number)) + return bignum_sign (XBIGNUM_DATA (number)) == 0 ? Qt : Qnil; +#endif +#ifdef HAVE_RATIO + else if (RATIOP (number)) + return ratio_sign (XRATIO_DATA (number)) == 0 ? Qt : Qnil; +#endif else if (FLOATP (number)) return XFLOAT_DATA (number) == 0.0 ? Qt : Qnil; +#ifdef HAVE_BIGFLOAT + else if (BIGFLOATP (number)) + return bigfloat_sign (XBIGFLOAT_DATA (number)) == 0 ? Qt : Qnil; +#endif else { number = wrong_type_argument (Qnumberp, number); @@ -1001,10 +1160,15 @@ Convert NUMBER to a string by printing it in decimal. Uses a minus sign if negative. NUMBER may be an integer or a floating point number. +If supported, it may also be a ratio. */ (number)) { +#ifdef WITH_NUMBER_TYPES + CHECK_NUMBER (number); +#else CHECK_INT_OR_FLOAT (number); +#endif if (FLOATP (number)) { @@ -1013,6 +1177,33 @@ float_to_string (pigbuf, XFLOAT_DATA (number)); return build_string (pigbuf); } +#ifdef HAVE_BIGNUM + if (BIGNUMP (number)) + { + char *str = bignum_to_string (XBIGNUM_DATA (number), 10); + Lisp_Object retval = build_string (str); + xfree (str, char *); + return retval; + } +#endif +#ifdef HAVE_RATIO + if (RATIOP (number)) + { + char *str = ratio_to_string (XRATIO_DATA (number), 10); + Lisp_Object retval = build_string (str); + xfree (str, char *); + return retval; + } +#endif +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (number)) + { + char *str = bigfloat_to_string (XBIGFLOAT_DATA (number), 10); + Lisp_Object retval = build_string (str); + xfree (str, char *); + return retval; + } +#endif { char buffer[DECIMAL_PRINT_SIZE (long)]; @@ -1037,6 +1228,7 @@ DEFUN ("string-to-number", Fstring_to_number, 1, 2, 0, /* Convert STRING to a number by parsing it as a number in base BASE. This parses both integers and floating point numbers. +If they are supported, it also reads ratios. It ignores leading spaces and tabs. If BASE is nil or omitted, base 10 is used. @@ -1067,8 +1259,36 @@ p++; if (isfloat_string (p) && b == 10) - return make_float (atof (p)); - + { +#ifdef HAVE_BIGFLOAT + if (ZEROP (Vdefault_float_precision)) +#endif + return make_float (atof (p)); +#ifdef HAVE_BIGFLOAT + else + { + bigfloat_set_prec (scratch_bigfloat, bigfloat_get_default_prec ()); + bigfloat_set_string (scratch_bigfloat, p, b); + return make_bigfloat_bf (scratch_bigfloat); + } +#endif + } + +#ifdef HAVE_RATIO + if (qxestrchr (p, '/') != NULL) + { + ratio_set_string (scratch_ratio, p, b); + return make_ratio_rt (scratch_ratio); + } +#endif /* HAVE_RATIO */ + +#ifdef HAVE_BIGNUM + /* GMP bignum_set_string returns random values when fed an empty string */ + if (*p == '\0') + return make_int (0); + bignum_set_string (scratch_bignum, p, b); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#else if (b == 10) { /* Use the system-provided functions for base 10. */ @@ -1101,6 +1321,7 @@ } return make_int (negative * v); } +#endif /* HAVE_BIGNUM */ } @@ -1110,6 +1331,49 @@ */ (int nargs, Lisp_Object *args)) { +#ifdef WITH_NUMBER_TYPES + REGISTER int i; + Lisp_Object accum = make_int (0), addend; + + for (i = 0; i < nargs; i++) + { + addend = args[i]; + switch (promote_args (&accum, &addend)) + { + case FIXNUM_T: + accum = make_integer (XREALINT (accum) + XREALINT (addend)); + break; +#ifdef HAVE_BIGNUM + case BIGNUM_T: + bignum_add (scratch_bignum, XBIGNUM_DATA (accum), + XBIGNUM_DATA (addend)); + accum = make_bignum_bg (scratch_bignum); + break; +#endif +#ifdef HAVE_RATIO + case RATIO_T: + ratio_add (scratch_ratio, XRATIO_DATA (accum), + XRATIO_DATA (addend)); + accum = make_ratio_rt (scratch_ratio); + break; +#endif + case FLOAT_T: + accum = make_float (XFLOAT_DATA (accum) + XFLOAT_DATA (addend)); + break; +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + bigfloat_set_prec (scratch_bigfloat, + max (XBIGFLOAT_GET_PREC (addend), + XBIGFLOAT_GET_PREC (accum))); + bigfloat_add (scratch_bigfloat, XBIGFLOAT_DATA (accum), + XBIGFLOAT_DATA (addend)); + accum = make_bigfloat_bf (scratch_bigfloat); + break; +#endif + } + } + return Fcanonicalize_number (accum); +#else /* !WITH_NUMBER_TYPES */ EMACS_INT iaccum = 0; Lisp_Object *args_end = args + nargs; @@ -1129,6 +1393,7 @@ } return make_int (iaccum); +#endif /* WITH_NUMBER_TYPES */ } DEFUN ("-", Fminus, 1, MANY, 0, /* @@ -1138,6 +1403,87 @@ */ (int nargs, Lisp_Object *args)) { +#ifdef WITH_NUMBER_TYPES + REGISTER int i; + Lisp_Object accum = args[0], subtrahend; + + if (nargs == 1) + { + if (CHARP (accum)) + accum = make_int (XCHAR (accum)); + else if (MARKERP (accum)) + accum = make_int (marker_position (accum)); + + /* Invert the sign of accum */ + CHECK_NUMBER (accum); + switch (get_number_type (accum)) + { + case FIXNUM_T: + return make_integer (-XREALINT (accum)); +#ifdef HAVE_BIGNUM + case BIGNUM_T: + bignum_neg (scratch_bignum, XBIGNUM_DATA (accum)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#endif +#ifdef HAVE_RATIO + case RATIO_T: + ratio_neg (scratch_ratio, XRATIO_DATA (accum)); + return make_ratio_rt (scratch_ratio); +#endif + case FLOAT_T: + return make_float (-XFLOAT_DATA (accum)); +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (accum)); + bigfloat_neg (scratch_bigfloat, XBIGFLOAT_DATA (accum)); + return make_bigfloat_bf (scratch_bigfloat); +#endif + } + } + else + { + /* Subtrace the remaining arguments from accum */ + for (i = 1; i < nargs; i++) + { + subtrahend = args[i]; + switch (promote_args (&accum, &subtrahend)) + { + case FIXNUM_T: + accum = make_integer (XREALINT (accum) - XREALINT (subtrahend)); + break; +#ifdef HAVE_BIGNUM + case BIGNUM_T: + bignum_sub (scratch_bignum, XBIGNUM_DATA (accum), + XBIGNUM_DATA (subtrahend)); + accum = make_bignum_bg (scratch_bignum); + break; +#endif +#ifdef HAVE_RATIO + case RATIO_T: + ratio_sub (scratch_ratio, XRATIO_DATA (accum), + XRATIO_DATA (subtrahend)); + accum = make_ratio_rt (scratch_ratio); + break; +#endif + case FLOAT_T: + accum = + make_float (XFLOAT_DATA (accum) - XFLOAT_DATA (subtrahend)); + break; +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + bigfloat_set_prec (scratch_bigfloat, + max (XBIGFLOAT_GET_PREC (subtrahend), + XBIGFLOAT_GET_PREC (accum))); + bigfloat_sub (scratch_bigfloat, XBIGFLOAT_DATA (accum), + XBIGFLOAT_DATA (subtrahend)); + accum = make_bigfloat_bf (scratch_bigfloat); + break; +#endif + } + } + } + return Fcanonicalize_number (accum); +#else /* !WITH_NUMBER_TYPES */ EMACS_INT iaccum; double daccum; Lisp_Object *args_end = args + nargs; @@ -1170,6 +1516,7 @@ for (; args < args_end; args++) daccum -= number_char_or_marker_to_double (*args); return make_float (daccum); +#endif /* WITH_NUMBER_TYPES */ } DEFUN ("*", Ftimes, 0, MANY, 0, /* @@ -1178,6 +1525,47 @@ */ (int nargs, Lisp_Object *args)) { +#ifdef WITH_NUMBER_TYPES + REGISTER int i; + /* Start with a bignum to avoid overflow */ + Lisp_Object accum = make_bignum (1L), multiplier; + + for (i = 0; i < nargs; i++) + { + multiplier = args[i]; + switch (promote_args (&accum, &multiplier)) + { +#ifdef HAVE_BIGNUM + case BIGNUM_T: + bignum_mul (scratch_bignum, XBIGNUM_DATA (accum), + XBIGNUM_DATA (multiplier)); + accum = make_bignum_bg (scratch_bignum); + break; +#endif +#ifdef HAVE_RATIO + case RATIO_T: + ratio_mul (scratch_ratio, XRATIO_DATA (accum), + XRATIO_DATA (multiplier)); + accum = make_ratio_rt (scratch_ratio); + break; +#endif + case FLOAT_T: + accum = make_float (XFLOAT_DATA (accum) * XFLOAT_DATA (multiplier)); + break; +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + bigfloat_set_prec (scratch_bigfloat, + max (XBIGFLOAT_GET_PREC (multiplier), + XBIGFLOAT_GET_PREC (accum))); + bigfloat_mul (scratch_bigfloat, XBIGFLOAT_DATA (accum), + XBIGFLOAT_DATA (multiplier)); + accum = make_bigfloat_bf (scratch_bigfloat); + break; +#endif + } + } + return Fcanonicalize_number (accum); +#else /* !WITH_NUMBER_TYPES */ EMACS_INT iaccum = 1; Lisp_Object *args_end = args + nargs; @@ -1197,8 +1585,78 @@ } return make_int (iaccum); +#endif /* WITH_NUMBER_TYPES */ } +#ifdef HAVE_RATIO +DEFUN ("div", Fdiv, 1, MANY, 0, /* +Same as `/', but dividing integers creates a ratio instead of truncating. +Note that this is a departure from Common Lisp, where / creates ratios when +dividing integers. Having a separate function lets us avoid breaking existing +Emacs Lisp code that expects / to do integer division. +*/ + (int nargs, Lisp_Object *args)) +{ + REGISTER int i; + Lisp_Object accum, divisor; + + if (nargs == 1) + { + i = 0; + accum = make_int (1); + } + else + { + i = 1; + accum = args[0]; + } + for (; i < nargs; i++) + { + divisor = args[i]; + switch (promote_args (&accum, &divisor)) + { + case FIXNUM_T: + if (XREALINT (divisor) == 0) goto divide_by_zero; + bignum_set_long (scratch_bignum, XREALINT (accum)); + bignum_set_long (scratch_bignum2, XREALINT (divisor)); + accum = make_ratio_bg (scratch_bignum, scratch_bignum2); + break; + case BIGNUM_T: + if (bignum_sign (XBIGNUM_DATA (divisor)) == 0) goto divide_by_zero; + accum = make_ratio_bg (XBIGNUM_DATA (accum), XBIGNUM_DATA (divisor)); + break; + case RATIO_T: + if (ratio_sign (XRATIO_DATA (divisor)) == 0) goto divide_by_zero; + ratio_div (scratch_ratio, XRATIO_DATA (accum), + XRATIO_DATA (divisor)); + accum = make_ratio_rt (scratch_ratio); + break; + case FLOAT_T: + if (XFLOAT_DATA (divisor) == 0.0) goto divide_by_zero; + accum = make_float (XFLOAT_DATA (accum) / XFLOAT_DATA (divisor)); + break; +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + if (bigfloat_sign (XBIGFLOAT_DATA (divisor)) == 0) + goto divide_by_zero; + bigfloat_set_prec (scratch_bigfloat, + max (XBIGFLOAT_GET_PREC (divisor), + XBIGFLOAT_GET_PREC (accum))); + bigfloat_div (scratch_bigfloat, XBIGFLOAT_DATA (accum), + XBIGFLOAT_DATA (divisor)); + accum = make_bigfloat_bf (scratch_bigfloat); + break; +#endif + } + } + return Fcanonicalize_number (accum); + + divide_by_zero: + Fsignal (Qarith_error, Qnil); + return Qnil; /* not (usually) reached */ +} +#endif /* HAVE_RATIO */ + DEFUN ("/", Fquo, 1, MANY, 0, /* Return first argument divided by all the remaining arguments. The arguments must be numbers, characters or markers. @@ -1206,6 +1664,65 @@ */ (int nargs, Lisp_Object *args)) { +#ifdef WITH_NUMBER_TYPES + REGISTER int i; + Lisp_Object accum, divisor; + + if (nargs == 1) + { + i = 0; + accum = make_int (1); + } + else + { + i = 1; + accum = args[0]; + } + for (; i < nargs; i++) + { + divisor = args[i]; + switch (promote_args (&accum, &divisor)) + { + case FIXNUM_T: + if (XREALINT (divisor) == 0) goto divide_by_zero; + accum = make_integer (XREALINT (accum) / XREALINT (divisor)); + break; +#ifdef HAVE_BIGNUM + case BIGNUM_T: + if (bignum_sign (XBIGNUM_DATA (divisor)) == 0) goto divide_by_zero; + bignum_div (scratch_bignum, XBIGNUM_DATA (accum), + XBIGNUM_DATA (divisor)); + accum = make_bignum_bg (scratch_bignum); + break; +#endif +#ifdef HAVE_RATIO + case RATIO_T: + if (ratio_sign (XRATIO_DATA (divisor)) == 0) goto divide_by_zero; + ratio_div (scratch_ratio, XRATIO_DATA (accum), + XRATIO_DATA (divisor)); + accum = make_ratio_rt (scratch_ratio); + break; +#endif + case FLOAT_T: + if (XFLOAT_DATA (divisor) == 0.0) goto divide_by_zero; + accum = make_float (XFLOAT_DATA (accum) / XFLOAT_DATA (divisor)); + break; +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + if (bigfloat_sign (XBIGFLOAT_DATA (divisor)) == 0) + goto divide_by_zero; + bigfloat_set_prec (scratch_bigfloat, + max (XBIGFLOAT_GET_PREC (divisor), + XBIGFLOAT_GET_PREC (accum))); + bigfloat_div (scratch_bigfloat, XBIGFLOAT_DATA (accum), + XBIGFLOAT_DATA (divisor)); + accum = make_bigfloat_bf (scratch_bigfloat); + break; +#endif + } + } + return Fcanonicalize_number (accum); +#else /* !WITH_NUMBER_TYPES */ EMACS_INT iaccum; double daccum; Lisp_Object *args_end = args + nargs; @@ -1251,6 +1768,7 @@ daccum /= dval; } return make_float (daccum); +#endif /* WITH_NUMBER_TYPES */ divide_by_zero: Fsignal (Qarith_error, Qnil); @@ -1259,12 +1777,59 @@ DEFUN ("max", Fmax, 1, MANY, 0, /* Return largest of all the arguments. -All arguments must be numbers, characters or markers. +All arguments must be real numbers, characters or markers. The value is always a number; markers and characters are converted to numbers. */ (int nargs, Lisp_Object *args)) { +#ifdef WITH_NUMBER_TYPES + REGISTER int i, maxindex = 0; + Lisp_Object comp1, comp2; + + while (!(CHARP (args[0]) || MARKERP (args[0]) || REALP (args[0]))) + args[0] = wrong_type_argument (Qnumber_char_or_marker_p, args[0]); + if (CHARP (args[0])) + args[0] = make_int (XCHAR (args[0])); + else if (MARKERP (args[0])) + args[0] = make_int (marker_position (args[0])); + for (i = 1; i < nargs; i++) + { + retry: + comp1 = args[maxindex]; + comp2 = args[i]; + switch (promote_args (&comp1, &comp2)) + { + case FIXNUM_T: + if (XREALINT (comp1) < XREALINT (comp2)) + maxindex = i; + break; +#ifdef HAVE_BIGNUM + case BIGNUM_T: + if (bignum_lt (XBIGNUM_DATA (comp1), XBIGNUM_DATA (comp2))) + maxindex = i; + break; +#endif +#ifdef HAVE_RATIO + case RATIO_T: + if (ratio_lt (XRATIO_DATA (comp1), XRATIO_DATA (comp2))) + maxindex = i; + break; +#endif + case FLOAT_T: + if (XFLOAT_DATA (comp1) < XFLOAT_DATA (comp2)) + maxindex = i; + break; +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + if (bigfloat_lt (XBIGFLOAT_DATA (comp1), XBIGFLOAT_DATA (comp2))) + maxindex = i; + break; +#endif + } + } + return args[maxindex]; +#else /* !WITH_NUMBER_TYPES */ EMACS_INT imax; double dmax; Lisp_Object *args_end = args + nargs; @@ -1303,6 +1868,7 @@ if (dmax < dval) dmax = dval; } return make_float (dmax); +#endif /* WITH_NUMBER_TYPES */ } DEFUN ("min", Fmin, 1, MANY, 0, /* @@ -1313,6 +1879,52 @@ */ (int nargs, Lisp_Object *args)) { +#ifdef WITH_NUMBER_TYPES + REGISTER int i, minindex = 0; + Lisp_Object comp1, comp2; + + while (!(CHARP (args[0]) || MARKERP (args[0]) || REALP (args[0]))) + args[0] = wrong_type_argument (Qnumber_char_or_marker_p, args[0]); + if (CHARP (args[0])) + args[0] = make_int (XCHAR (args[0])); + else if (MARKERP (args[0])) + args[0] = make_int (marker_position (args[0])); + for (i = 1; i < nargs; i++) + { + comp1 = args[minindex]; + comp2 = args[i]; + switch (promote_args (&comp1, &comp2)) + { + case FIXNUM_T: + if (XREALINT (comp1) > XREALINT (comp2)) + minindex = i; + break; +#ifdef HAVE_BIGNUM + case BIGNUM_T: + if (bignum_gt (XBIGNUM_DATA (comp1), XBIGNUM_DATA (comp2))) + minindex = i; + break; +#endif +#ifdef HAVE_RATIO + case RATIO_T: + if (ratio_gt (XRATIO_DATA (comp1), XRATIO_DATA (comp2))) + minindex = i; + break; +#endif + case FLOAT_T: + if (XFLOAT_DATA (comp1) > XFLOAT_DATA (comp2)) + minindex = i; + break; +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + if (bigfloat_gt (XBIGFLOAT_DATA (comp1), XBIGFLOAT_DATA (comp2))) + minindex = i; + break; +#endif + } + } + return args[minindex]; +#else /* !WITH_NUMBER_TYPES */ EMACS_INT imin; double dmin; Lisp_Object *args_end = args + nargs; @@ -1351,6 +1963,7 @@ if (dmin > dval) dmin = dval; } return make_float (dmin); +#endif /* WITH_NUMBER_TYPES */ } DEFUN ("logand", Flogand, 0, MANY, 0, /* @@ -1359,6 +1972,43 @@ */ (int nargs, Lisp_Object *args)) { +#ifdef HAVE_BIGNUM + REGISTER int i; + Lisp_Object result, other; + + if (nargs == 0) + return make_int (~0); + + while (!(CHARP (args[0]) || MARKERP (args[0]) || INTEGERP (args[0]))) + args[0] = wrong_type_argument (Qnumber_char_or_marker_p, args[0]); + + result = args[0]; + if (CHARP (result)) + result = make_int (XCHAR (result)); + else if (MARKERP (result)) + result = make_int (marker_position (result)); + for (i = 1; i < nargs; i++) + { + while (!(CHARP (args[i]) || MARKERP (args[i]) || INTEGERP (args[i]))) + args[i] = wrong_type_argument (Qnumber_char_or_marker_p, args[i]); + other = args[i]; + switch (promote_args (&result, &other)) + { + case FIXNUM_T: + /* This looks evil, but it isn't. The bits identifying the objects + as fixnums will be present in both, so & will preserve them. + The only bits possibly turned off are the actual data bits. */ + result &= other; + break; + case BIGNUM_T: + bignum_and (scratch_bignum, XBIGNUM_DATA (result), + XBIGNUM_DATA (other)); + result = make_bignum_bg (scratch_bignum); + break; + } + } + return Fcanonicalize_number (result); +#else /* !HAVE_BIGNUM */ EMACS_INT bits = ~0; Lisp_Object *args_end = args + nargs; @@ -1366,6 +2016,7 @@ bits &= integer_char_or_marker_to_int (*args++); return make_int (bits); +#endif /* HAVE_BIGNUM */ } DEFUN ("logior", Flogior, 0, MANY, 0, /* @@ -1374,6 +2025,43 @@ */ (int nargs, Lisp_Object *args)) { +#ifdef HAVE_BIGNUM + REGISTER int i; + Lisp_Object result, other; + + if (nargs == 0) + return make_int (0); + + while (!(CHARP (args[0]) || MARKERP (args[0]) || INTEGERP (args[0]))) + args[0] = wrong_type_argument (Qnumber_char_or_marker_p, args[0]); + + result = args[0]; + if (CHARP (result)) + result = make_int (XCHAR (result)); + else if (MARKERP (result)) + result = make_int (marker_position (result)); + for (i = 1; i < nargs; i++) + { + while (!(CHARP (args[i]) || MARKERP (args[i]) || INTEGERP (args[i]))) + args[i] = wrong_type_argument (Qnumber_char_or_marker_p, args[i]); + other = args[i]; + switch (promote_args (&result, &other)) + { + case FIXNUM_T: + /* This looks evil, but it isn't. The bits identifying the objects + as fixnums are the same in both, so | will preserve them. The + only bits possibly turned on are the actual data bits. */ + result |= other; + break; + case BIGNUM_T: + bignum_ior (scratch_bignum, XBIGNUM_DATA (result), + XBIGNUM_DATA (other)); + result = make_bignum_bg (scratch_bignum); + break; + } + } + return Fcanonicalize_number (result); +#else /* !HAVE_BIGNUM */ EMACS_INT bits = 0; Lisp_Object *args_end = args + nargs; @@ -1381,6 +2069,7 @@ bits |= integer_char_or_marker_to_int (*args++); return make_int (bits); +#endif /* HAVE_BIGNUM */ } DEFUN ("logxor", Flogxor, 0, MANY, 0, /* @@ -1389,6 +2078,39 @@ */ (int nargs, Lisp_Object *args)) { +#ifdef HAVE_BIGNUM + REGISTER int i; + Lisp_Object result, other; + + if (nargs == 0) + return make_int (0); + + while (!(CHARP (args[0]) || MARKERP (args[0]) || INTEGERP (args[0]))) + args[0] = wrong_type_argument (Qnumber_char_or_marker_p, args[0]); + + result = args[0]; + if (CHARP (result)) + result = make_int (XCHAR (result)); + else if (MARKERP (result)) + result = make_int (marker_position (result)); + for (i = 1; i < nargs; i++) + { + while (!(CHARP (args[i]) || MARKERP (args[i]) || INTEGERP (args[i]))) + args[i] = wrong_type_argument (Qnumber_char_or_marker_p, args[i]); + other = args[i]; + if (promote_args (&result, &other) == FIXNUM_T) + { + result = make_int (XREALINT (result) ^ XREALINT (other)); + } + else + { + bignum_xor (scratch_bignum, XBIGNUM_DATA (result), + XBIGNUM_DATA (other)); + result = make_bignum_bg (scratch_bignum); + } + } + return Fcanonicalize_number (result); +#else /* !HAVE_BIGNUM */ EMACS_INT bits = 0; Lisp_Object *args_end = args + nargs; @@ -1396,6 +2118,7 @@ bits ^= integer_char_or_marker_to_int (*args++); return make_int (bits); +#endif /* !HAVE_BIGNUM */ } DEFUN ("lognot", Flognot, 1, 1, 0, /* @@ -1404,6 +2127,13 @@ */ (number)) { +#ifdef HAVE_BIGNUM + if (BIGNUMP (number)) + { + bignum_not (scratch_bignum, XBIGNUM_DATA (number)); + return make_bignum_bg (scratch_bignum); + } +#endif /* HAVE_BIGNUM */ return make_int (~ integer_char_or_marker_to_int (number)); } @@ -1413,6 +2143,27 @@ */ (number1, number2)) { +#ifdef HAVE_BIGNUM + while (!(CHARP (number1) || MARKERP (number1) || INTEGERP (number1))) + number1 = wrong_type_argument (Qnumber_char_or_marker_p, number1); + while (!(CHARP (number2) || MARKERP (number2) || INTEGERP (number2))) + number2 = wrong_type_argument (Qnumber_char_or_marker_p, number2); + + if (promote_args (&number1, &number2) == FIXNUM_T) + { + if (XREALINT (number2) == 0) + Fsignal (Qarith_error, Qnil); + return make_int (XREALINT (number1) % XREALINT (number2)); + } + else + { + if (bignum_sign (XBIGNUM_DATA (number2)) == 0) + Fsignal (Qarith_error, Qnil); + bignum_mod (scratch_bignum, XBIGNUM_DATA (number1), + XBIGNUM_DATA (number2)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } +#else /* !HAVE_BIGNUM */ EMACS_INT ival1 = integer_char_or_marker_to_int (number1); EMACS_INT ival2 = integer_char_or_marker_to_int (number2); @@ -1420,6 +2171,7 @@ Fsignal (Qarith_error, Qnil); return make_int (ival1 % ival2); +#endif /* HAVE_BIGNUM */ } /* Note, ANSI *requires* the presence of the fmod() library routine. @@ -1445,6 +2197,62 @@ */ (x, y)) { +#ifdef WITH_NUMBER_TYPES + while (!(CHARP (x) || MARKERP (x) || REALP (x))) + x = wrong_type_argument (Qnumber_char_or_marker_p, x); + while (!(CHARP (y) || MARKERP (y) || REALP (y))) + y = wrong_type_argument (Qnumber_char_or_marker_p, y); + switch (promote_args (&x, &y)) + { + case FIXNUM_T: + { + EMACS_INT ival; + if (XREALINT (y) == 0) goto divide_by_zero; + ival = XREALINT (x) % XREALINT (y); + /* If the "remainder" comes out with the wrong sign, fix it. */ + if (XREALINT (y) < 0 ? ival > 0 : ival < 0) + ival += XREALINT (y); + return make_int (ival); + } +#ifdef HAVE_BIGNUM + case BIGNUM_T: + if (bignum_sign (XBIGNUM_DATA (y)) == 0) goto divide_by_zero; + bignum_mod (scratch_bignum, XBIGNUM_DATA (x), XBIGNUM_DATA (y)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#endif +#ifdef HAVE_RATIO + case RATIO_T: + if (ratio_sign (XRATIO_DATA (y)) == 0) goto divide_by_zero; + ratio_div (scratch_ratio, XRATIO_DATA (x), XRATIO_DATA (y)); + bignum_div (scratch_bignum, ratio_numerator (scratch_ratio), + ratio_denominator (scratch_ratio)); + ratio_set_bignum (scratch_ratio, scratch_bignum); + ratio_mul (scratch_ratio, scratch_ratio, XRATIO_DATA (y)); + ratio_sub (scratch_ratio, XRATIO_DATA (x), scratch_ratio); + return Fcanonicalize_number (make_ratio_rt (scratch_ratio)); +#endif + case FLOAT_T: + { + double dval; + if (XFLOAT_DATA (y) == 0.0) goto divide_by_zero; + dval = fmod (XFLOAT_DATA (x), XFLOAT_DATA (y)); + /* If the "remainder" comes out with the wrong sign, fix it. */ + if (XFLOAT_DATA (y) < 0 ? dval > 0 : dval < 0) + dval += XFLOAT_DATA (y); + return make_float (dval); + } +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + bigfloat_set_prec (scratch_bigfloat, + max (XBIGFLOAT_GET_PREC (x), XBIGFLOAT_GET_PREC (y))); + bigfloat_div (scratch_bigfloat, XBIGFLOAT_DATA (x), XBIGFLOAT_DATA (y)); + bigfloat_trunc (scratch_bigfloat, scratch_bigfloat); + bigfloat_mul (scratch_bigfloat, scratch_bigfloat, XBIGFLOAT_DATA (y)); + bigfloat_sub (scratch_bigfloat, XBIGFLOAT_DATA (x), scratch_bigfloat); + return make_bigfloat_bf (scratch_bigfloat); +#endif + } +#else /* !WITH_NUMBER_TYPES */ int_or_double iod1, iod2; number_char_or_marker_to_int_or_double (x, &iod1); number_char_or_marker_to_int_or_double (y, &iod2); @@ -1475,6 +2283,7 @@ return make_int (ival); } +#endif /* WITH_NUMBER_TYPES */ divide_by_zero: Fsignal (Qarith_error, Qnil); @@ -1485,6 +2294,8 @@ Return VALUE with its bits shifted left by COUNT. If COUNT is negative, shifting is actually to the right. In this case, the sign bit is duplicated. +This function cannot be applied to bignums, as there is no leftmost sign bit +to be duplicated. Use `lsh' instead. */ (value, count)) { @@ -1503,12 +2314,47 @@ */ (value, count)) { +#ifdef HAVE_BIGNUM + while (!(CHARP (value) || MARKERP (value) || INTEGERP (value))) + wrong_type_argument (Qnumber_char_or_marker_p, value); + CONCHECK_INTEGER (count); + + if (promote_args (&value, &count) == FIXNUM_T) + { + if (XREALINT (count) <= 0) + return make_int (XREALINT (value) >> -XREALINT (count)); + /* Use bignums to avoid overflow */ + bignum_set_long (scratch_bignum2, XREALINT (value)); + bignum_lshift (scratch_bignum, scratch_bignum2, XREALINT (count)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } + else + { + if (bignum_sign (XBIGNUM_DATA (count)) <= 0) + { + bignum_neg (scratch_bignum, XBIGNUM_DATA (count)); + if (!bignum_fits_ulong_p (scratch_bignum)) + args_out_of_range (Qnumber_char_or_marker_p, count); + bignum_rshift (scratch_bignum2, XBIGNUM_DATA (value), + bignum_to_ulong (scratch_bignum)); + } + else + { + if (!bignum_fits_ulong_p (XBIGNUM_DATA (count))) + args_out_of_range (Qnumber_char_or_marker_p, count); + bignum_lshift (scratch_bignum2, XBIGNUM_DATA (value), + bignum_to_ulong (XBIGNUM_DATA (count))); + } + return Fcanonicalize_number (make_bignum_bg (scratch_bignum2)); + } +#else /* !HAVE_BIGNUM */ CHECK_INT_COERCE_CHAR (value); CONCHECK_INT (count); return make_int (XINT (count) > 0 ? XUINT (value) << XINT (count) : XUINT (value) >> -XINT (count)); +#endif /* HAVE_BIGNUM */ } DEFUN ("1+", Fadd1, 1, 1, 0, /* @@ -1519,10 +2365,37 @@ { retry: - if (INTP (number)) return make_int (XINT (number) + 1); - if (CHARP (number)) return make_int (XCHAR (number) + 1); - if (MARKERP (number)) return make_int (marker_position (number) + 1); + if (INTP (number)) return make_integer (XINT (number) + 1); + if (CHARP (number)) return make_integer (XCHAR (number) + 1); + if (MARKERP (number)) return make_integer (marker_position (number) + 1); if (FLOATP (number)) return make_float (XFLOAT_DATA (number) + 1.0); +#ifdef HAVE_BIGNUM + if (BIGNUMP (number)) + { + bignum_set_long (scratch_bignum, 1L); + bignum_add (scratch_bignum2, XBIGNUM_DATA (number), scratch_bignum); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum2)); + } +#endif +#ifdef HAVE_RATIO + if (RATIOP (number)) + { + ratio_set_long (scratch_ratio, 1L); + ratio_add (scratch_ratio, XRATIO_DATA (number), scratch_ratio); + /* No need to canonicalize after adding 1 */ + return make_ratio_rt (scratch_ratio); + } +#endif +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (number)) + { + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (number)); + bigfloat_set_long (scratch_bigfloat, 1L); + bigfloat_add (scratch_bigfloat, XBIGFLOAT_DATA (number), + scratch_bigfloat); + return make_bigfloat_bf (scratch_bigfloat); + } +#endif number = wrong_type_argument (Qnumber_char_or_marker_p, number); goto retry; @@ -1536,10 +2409,37 @@ { retry: - if (INTP (number)) return make_int (XINT (number) - 1); - if (CHARP (number)) return make_int (XCHAR (number) - 1); - if (MARKERP (number)) return make_int (marker_position (number) - 1); + if (INTP (number)) return make_integer (XINT (number) - 1); + if (CHARP (number)) return make_integer (XCHAR (number) - 1); + if (MARKERP (number)) return make_integer (marker_position (number) - 1); if (FLOATP (number)) return make_float (XFLOAT_DATA (number) - 1.0); +#ifdef HAVE_BIGNUM + if (BIGNUMP (number)) + { + bignum_set_long (scratch_bignum, 1L); + bignum_sub (scratch_bignum2, XBIGNUM_DATA (number), scratch_bignum); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum2)); + } +#endif +#ifdef HAVE_RATIO + if (RATIOP (number)) + { + ratio_set_long (scratch_ratio, 1L); + ratio_sub (scratch_ratio, XRATIO_DATA (number), scratch_ratio); + /* No need to canonicalize after subtracting 1 */ + return make_ratio_rt (scratch_ratio); + } +#endif +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (number)) + { + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (number)); + bigfloat_set_long (scratch_bigfloat, 1L); + bigfloat_sub (scratch_bigfloat, XBIGFLOAT_DATA (number), + scratch_bigfloat); + return make_bigfloat_bf (scratch_bigfloat); + } +#endif number = wrong_type_argument (Qnumber_char_or_marker_p, number); goto retry; @@ -2487,6 +3387,7 @@ DEFSYMBOL (Qintegerp); DEFSYMBOL (Qcharacterp); DEFSYMBOL (Qnatnump); + DEFSYMBOL (Qnonnegativep); DEFSYMBOL (Qstringp); DEFSYMBOL (Qarrayp); DEFSYMBOL (Qsequencep); @@ -2508,6 +3409,9 @@ DEFSUBR (Fwrong_type_argument); +#ifdef HAVE_RATIO + DEFSUBR (Fdiv); +#endif DEFSUBR (Feq); DEFSUBR (Fold_eq); DEFSUBR (Fnull); @@ -2523,7 +3427,11 @@ DEFSUBR (Fchar_to_int); DEFSUBR (Fint_to_char); DEFSUBR (Fchar_or_char_int_p); +#ifdef HAVE_BIGNUM + DEFSUBR (Ffixnump); +#else DEFSUBR (Fintegerp); +#endif DEFSUBR (Finteger_or_marker_p); DEFSUBR (Finteger_or_char_p); DEFSUBR (Finteger_char_or_marker_p); @@ -2532,6 +3440,7 @@ DEFSUBR (Fnumber_char_or_marker_p); DEFSUBR (Ffloatp); DEFSUBR (Fnatnump); + DEFSUBR (Fnonnegativep); DEFSUBR (Fsymbolp); DEFSUBR (Fkeywordp); DEFSUBR (Fstringp);
--- a/src/depend Mon Apr 05 21:50:47 2004 +0000 +++ b/src/depend Mon Apr 05 22:50:11 2004 +0000 @@ -11,7 +11,7 @@ LISP_H= #else CONFIG_H=config.h -LISP_H=lisp.h compiler.h config.h dumper.h general-slots.h lrecord.h symeval.h symsinit.h text.h $(LISP_UNION_H) +LISP_H=lisp.h compiler.h config.h dumper.h general-slots.h lrecord.h number-gmp.h number-mp.h number.h symeval.h symsinit.h text.h $(LISP_UNION_H) #endif #if defined(HAVE_MS_WINDOWS) @@ -195,6 +195,9 @@ nt.o: $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h intl-auto-encap-win32.h ndir.h process.h sysdir.h sysfile.h sysproc.h syspwd.h syssignal.h systime.h syswindows.h ntheap.o: $(LISP_H) intl-auto-encap-win32.h sysdep.h syswindows.h ntplay.o: $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h intl-auto-encap-win32.h sound.h sysfile.h syswindows.h +number-gmp.o: $(LISP_H) +number-mp.o: $(LISP_H) +number.o: $(LISP_H) objects.o: $(LISP_H) buffer.h bufslots.h casetab.h charset.h chartab.h conslots.h console-impl.h console-tty.h console.h device-impl.h device.h devslots.h elhash.h faces.h frame.h glyphs.h objects-impl.h objects.h redisplay.h scrollbar.h specifier.h systty.h window-impl.h window.h winslots.h offix.o: offix-cursors.h offix-types.h offix.h xintrinsic.h opaque.o: $(LISP_H) opaque.h
--- a/src/doprnt.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/doprnt.c Mon Apr 05 22:50:11 2004 +0000 @@ -6,6 +6,7 @@ Rewritten by mly to use varargs.h. Rewritten from scratch by Ben Wing (February 1995) for Mule; expanded to full printf spec. + Support for bignums, ratios, and bigfloats added April 2004 by Jerry James. This file is part of XEmacs. @@ -33,11 +34,24 @@ #include "lstream.h" static const char * const valid_flags = "-+ #0"; -static const char * const valid_converters = "dic" "ouxX" "feEgG" "sS"; +static const char * const valid_converters = "dic" "ouxX" "feEgG" "sS" +#if defined(HAVE_BIGNUM) || defined(HAVE_RATIO) + "npyY" +#endif +#ifdef HAVE_BIGFLOAT + "FhHkK" +#endif + ; static const char * const int_converters = "dic"; static const char * const unsigned_int_converters = "ouxX"; static const char * const double_converters = "feEgG"; static const char * const string_converters = "sS"; +#if defined(HAVE_BIGNUM) || defined(HAVE_RATIO) +static const char * const bignum_converters = "npyY"; +#endif +#ifdef HAVE_BIGFLOAT +static const char * const bigfloat_converters = "FhHkK"; +#endif typedef struct printf_spec printf_spec; struct printf_spec @@ -70,6 +84,7 @@ unsigned long ul; double d; Ibyte *bp; + Lisp_Object obj; }; /* We maintain a list of all the % specs in the specification, @@ -385,6 +400,14 @@ arg.d = va_arg (vargs, double); else if (strchr (string_converters, ch)) arg.bp = va_arg (vargs, Ibyte *); +#if defined(HAVE_BIGNUM) || defined(HAVE_RATIO) + else if (strchr (bignum_converters, ch)) + arg.obj = va_arg (vargs, Lisp_Object); +#endif +#ifdef HAVE_BIGFLOAT + else if (strchr (bigfloat_converters, ch)) + arg.obj = va_arg (vargs, Lisp_Object); +#endif else abort (); Dynarr_add (args, arg); @@ -568,27 +591,121 @@ Lisp_Object obj = largs[spec->argnum - 1]; if (CHARP (obj)) obj = make_int (XCHAR (obj)); +#ifdef WITH_NUMBER_TYPES + if (!NUMBERP (obj)) +#else if (!INT_OR_FLOATP (obj)) +#endif { syntax_error ("format specifier %%%c doesn't match argument type", make_char (ch)); } else if (strchr (double_converters, ch)) - arg.d = XFLOATINT (obj); + { +#ifdef WITH_NUMBER_TYPES + if (INTP (obj) || FLOATP (obj)) + arg.d = XFLOATINT (obj); +#ifdef HAVE_BIGNUM + else if (BIGNUMP (obj)) + arg.d = bignum_to_double (XBIGNUM_DATA (obj)); +#endif +#ifdef HAVE_RATIO + else if (RATIOP (obj)) + arg.d = ratio_to_double (XRATIO_DATA (obj)); +#endif +#ifdef HAVE_BIGFLOAT + else if (BIGFLOATP (obj)) + { + arg.obj = obj; + switch (ch) + { + case 'f': ch = 'F'; break; + case 'e': ch = 'h'; break; + case 'E': ch = 'H'; break; + case 'g': ch = 'k'; break; + case 'G': ch = 'K'; break; + } + } +#endif +#else /* !WITH_NUMBER_TYPES */ + arg.d = XFLOATINT (obj); +#endif /* WITH_NUMBER_TYPES */ + } else { if (FLOATP (obj)) obj = Ftruncate (obj); - - if (strchr (unsigned_int_converters, ch)) - arg.ul = (unsigned long) XINT (obj); - else - arg.l = XINT (obj); +#ifdef HAVE_BIGFLOAT + else if (BIGFLOATP (obj)) + { +#ifdef HAVE_BIGNUM + bignum_set_bigfloat (scratch_bignum, + XBIGFLOAT_DATA (obj)); + if (strchr (unsigned_int_converters, ch) && + bignum_sign (scratch_bignum) < 0) + dead_wrong_type_argument (Qnonnegativep, obj); + obj = + Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#else /* !HAVE_BIGNUM */ + obj = make_int (bigfloat_to_long (XBIGFLOAT_DATA (obj))); +#endif /* HAVE_BIGNUM */ + } +#endif /* HAVE_BIGFLOAT */ +#ifdef HAVE_RATIO + else if (RATIOP (obj)) + { + arg.obj = obj; + switch (ch) + { + case 'i': case 'd': ch = 'n'; break; + case 'o': ch = 'p'; break; + case 'x': ch = 'y'; break; + case 'X': ch = 'Y'; break; + default: /* ch == 'u' */ + if (strchr (unsigned_int_converters, ch) && + ratio_sign (XRATIO_DATA (obj)) < 0) + dead_wrong_type_argument (Qnonnegativep, obj); + else + ch = 'n'; + } + } +#endif +#ifdef HAVE_BIGNUM + if (BIGNUMP (obj)) + { + arg.obj = obj; + switch (ch) + { + case 'i': case 'd': ch = 'n'; break; + case 'o': ch = 'p'; break; + case 'x': ch = 'y'; break; + case 'X': ch = 'Y'; break; + default: /* ch == 'u' */ + if (strchr (unsigned_int_converters, ch) && + bignum_sign (XBIGNUM_DATA (obj)) < 0) + dead_wrong_type_argument (Qnatnump, obj); + else + ch = 'n'; + } + } +#endif + if (INTP (obj)) + { + if (strchr (unsigned_int_converters, ch)) + { +#ifdef HAVE_BIGNUM + if (XINT (obj) < 0) + dead_wrong_type_argument (Qnatnump, obj); +#endif + arg.ul = (unsigned long) XUINT (obj); + } + else + arg.l = XINT (obj); + } } } - if (ch == 'c') { Ichar a; @@ -605,6 +722,44 @@ doprnt_2 (stream, charbuf, charlen, spec->minwidth, -1, spec->minus_flag, spec->zero_flag); } +#if defined(HAVE_BIGNUM) || defined(HAVE_RATIO) + else if (strchr (bignum_converters, ch)) + { +#ifdef HAVE_BIGNUM + if (BIGNUMP (arg.obj)) + { + char *text_to_print = + bignum_to_string (XBIGNUM_DATA (arg.obj), + ch == 'n' ? 10 : + (ch == 'p' ? 8 : 16)); + doprnt_2 (stream, text_to_print, strlen (text_to_print), + spec->minwidth, -1, spec->minus_flag, + spec->zero_flag); + } +#endif +#ifdef HAVE_RATIO + if (RATIOP (arg.obj)) + { + char *text_to_print = + ratio_to_string (XRATIO_DATA (arg.obj), + ch == 'n' ? 10 : + (ch == 'p' ? 8 : 16)); + doprnt_2 (stream, text_to_print, strlen (text_to_print), + spec->minwidth, -1, spec->minus_flag, + spec->zero_flag); + } +#endif + } +#endif /* HAVE_BIGNUM || HAVE_RATIO */ +#ifdef HAVE_BIGFLOAT + else if (strchr (bigfloat_converters, ch)) + { + char *text_to_print = + bigfloat_to_string (XBIGFLOAT_DATA (arg.obj), 10); + doprnt_2 (stream, text_to_print, strlen (text_to_print), + spec->minwidth, -1, spec->minus_flag, spec->zero_flag); + } +#endif /* HAVE_BIGFLOAT */ else { /* ASCII Decimal representation uses 2.4 times as many
--- a/src/emacs.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/emacs.c Mon Apr 05 22:50:11 2004 +0000 @@ -1301,6 +1301,9 @@ #ifdef HAVE_SHLIB syms_of_module (); #endif +#ifdef WITH_NUMBER_TYPES + syms_of_number (); +#endif syms_of_objects (); syms_of_print (); #if !defined (NO_SUBPROCESSES) @@ -1816,6 +1819,9 @@ vars_of_dired_mswindows (); vars_of_nt (); #endif +#ifdef WITH_NUMBER_TYPES + vars_of_number (); +#endif vars_of_objects (); vars_of_print (); @@ -2275,6 +2281,12 @@ init_initial_directory (); /* get the directory to use for the "*scratch*" buffer, etc. */ +#ifdef WITH_NUMBER_TYPES + /* Set up bignums, ratios, bigfloats, complex numbers. + This must be done before the Lisp reader is set up. */ + init_number (); +#endif + init_lread (); /* Set up the Lisp reader. */ init_cmdargs (argc, (Extbyte **) argv, skip_args); /* Create list Vcommand_line_args */
--- a/src/floatfns.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/floatfns.c Mon Apr 05 22:50:11 2004 +0000 @@ -119,10 +119,15 @@ /* Convert float to Lisp Integer if it fits, else signal a range - error using the given arguments. */ + error using the given arguments. If bignums are available, range errors + are never signaled. */ static Lisp_Object float_to_int (double x, const char *name, Lisp_Object num, Lisp_Object num2) { +#ifdef HAVE_BIGNUM + bignum_set_double (scratch_bignum, x); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#else if (x >= ((EMACS_INT) 1 << (VALBITS-1)) || x <= - ((EMACS_INT) 1 << (VALBITS-1)) - (EMACS_INT) 1) { @@ -132,6 +137,7 @@ range_error (name, num); } return (make_int ((EMACS_INT) x)); +#endif /* HAVE_BIGNUM */ } @@ -199,6 +205,21 @@ if (INTP (num)) return (double) XINT (num); +#ifdef HAVE_BIGNUM + if (BIGNUMP (num)) + return bignum_to_double (XBIGNUM_DATA (num)); +#endif + +#ifdef HAVE_RATIO + if (RATIOP (num)) + return ratio_to_double (XRATIO_DATA (num)); +#endif + +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (num)) + return bigfloat_to_double (XBIGFLOAT_DATA (num)); +#endif + return extract_float (wrong_type_argument (Qnumberp, num)); } @@ -421,6 +442,21 @@ */ (number1, number2)) { +#ifdef HAVE_BIGNUM + if (INTEGERP (number1) && INTP (number2)) + { + if (INTP (number1)) + { + bignum_set_long (scratch_bignum2, XREALINT (number1)); + bignum_pow (scratch_bignum, scratch_bignum2, XREALINT (number2)); + } + else + bignum_pow (scratch_bignum, XBIGNUM_DATA (number1), + XREALINT (number2)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } +#endif + if (INTP (number1) && /* common lisp spec */ INTP (number2)) /* don't promote, if both are ints */ { @@ -451,6 +487,23 @@ return make_int (retval); } +#if defined(HAVE_BIGFLOAT) && defined(bigfloat_pow) + if (BIGFLOATP (number1) && INTEGERP (number2)) + { + unsigned long exp; + +#ifdef HAVE_BIGNUM + if (BIGNUMP (number2)) + exp = bignum_to_ulong (XBIGNUM_DATA (number2)); + else +#endif + exp = XUINT (number2); + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (number1)); + bigfloat_pow (scratch_bigfloat, XBIGFLOAT_DATA (number1), exp); + return make_bigfloat_bf (scratch_bigfloat); + } +#endif + { double f1 = extract_float (number1); double f2 = extract_float (number2); @@ -516,7 +569,17 @@ */ (number)) { - double d = extract_float (number); + double d; + +#if defined(HAVE_BIGFLOAT) && defined(bigfloat_sqrt) + if (BIGFLOATP (number)) + { + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (number)); + bigfloat_sqrt (scratch_bigfloat, XBIGFLOAT_DATA (number)); + return make_bigfloat_bf (scratch_bigfloat); + } +#endif /* HAVE_BIGFLOAT */ + d = extract_float (number); #ifdef FLOAT_CHECK_DOMAIN if (d < 0.0) domain_error ("sqrt", number); @@ -648,7 +711,43 @@ } if (INTP (number)) +#ifdef HAVE_BIGNUM + /* The most negative Lisp fixnum will overflow */ + return (XINT (number) >= 0) ? number : make_integer (- XINT (number)); +#else return (XINT (number) >= 0) ? number : make_int (- XINT (number)); +#endif + +#ifdef HAVE_BIGNUM + if (BIGNUMP (number)) + { + if (bignum_sign (XBIGNUM_DATA (number)) >= 0) + return number; + bignum_abs (scratch_bignum, XBIGNUM_DATA (number)); + return make_bignum_bg (scratch_bignum); + } +#endif + +#ifdef HAVE_RATIO + if (RATIOP (number)) + { + if (ratio_sign (XRATIO_DATA (number)) >= 0) + return number; + ratio_abs (scratch_ratio, XRATIO_DATA (number)); + return make_ratio_rt (scratch_ratio); + } +#endif + +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (number)) + { + if (bigfloat_sign (XBIGFLOAT_DATA (number)) >= 0) + return number; + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (number)); + bigfloat_abs (scratch_bigfloat, XBIGFLOAT_DATA (number)); + return make_bigfloat_bf (scratch_bigfloat); + } +#endif return Fabs (wrong_type_argument (Qnumberp, number)); } @@ -661,6 +760,29 @@ if (INTP (number)) return make_float ((double) XINT (number)); +#ifdef HAVE_BIGNUM + if (BIGFLOATP (number)) + { +#ifdef HAVE_BIGFLOAT + if (ZEROP (Vdefault_float_precision)) +#endif + return make_float (bignum_to_double (XBIGNUM_DATA (number))); +#ifdef HAVE_BIGFLOAT + else + { + bigfloat_set_prec (scratch_bigfloat, bigfloat_get_default_prec ()); + bigfloat_set_bignum (scratch_bigfloat, XBIGNUM_DATA (number)); + return make_bigfloat_bf (scratch_bigfloat); + } +#endif /* HAVE_BIGFLOAT */ + } +#endif /* HAVE_BIGNUM */ + +#ifdef HAVE_RATIO + if (RATIOP (number)) + make_float (ratio_to_double (XRATIO_DATA (number))); +#endif + if (FLOATP (number)) /* give 'em the same float back */ return number; @@ -730,9 +852,36 @@ return (float_to_int (d, "ceiling", number, Qunbound)); } +#ifdef HAVE_BIGNUM + if (INTEGERP (number)) +#else if (INTP (number)) +#endif return number; +#ifdef HAVE_RATIO + if (RATIOP (number)) + { + bignum_ceil (scratch_bignum, XRATIO_NUMERATOR (number), + XRATIO_DENOMINATOR (number)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } +#endif + +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (number)) + { + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (number)); + bigfloat_ceil (scratch_bigfloat, XBIGFLOAT_DATA (number)); +#ifdef HAVE_BIGNUM + bignum_set_bigfloat (scratch_bignum, scratch_bigfloat); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#else + return make_int ((EMACS_INT) bigfloat_to_long (scratch_bigfloat)); +#endif /* HAVE_BIGNUM */ + } +#endif /* HAVE_BIGFLOAT */ + return Fceiling (wrong_type_argument (Qnumberp, number)); } @@ -744,6 +893,99 @@ */ (number, divisor)) { +#ifdef WITH_NUMBER_TYPES + CHECK_REAL (number); + if (NILP (divisor)) + { + if (FLOATP (number)) + { + double d; + IN_FLOAT ((d = floor (XFLOAT_DATA (number))), "floor", number); + return (float_to_int (d, "floor", number, Qunbound)); + } +#ifdef HAVE_RATIO + else if (RATIOP (number)) + { + bignum_floor (scratch_bignum, XRATIO_NUMERATOR (number), + XRATIO_DENOMINATOR (number)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } +#endif +#ifdef HAVE_BIGFLOAT + else if (BIGFLOATP (number)) + { + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (number)); + bigfloat_floor (scratch_bigfloat, XBIGFLOAT_DATA (number)); + return make_bigfloat_bf (scratch_bigfloat); + } +#endif + return number; + } + else + { + CHECK_REAL (divisor); + switch (promote_args (&number, &divisor)) + { + case FIXNUM_T: + { + EMACS_INT i1 = XREALINT (number); + EMACS_INT i2 = XREALINT (divisor); + + if (i2 == 0) + Fsignal (Qarith_error, Qnil); + + /* With C's /, the result is implementation-defined if either + operand is negative, so use only nonnegative operands. */ + i1 = (i2 < 0 + ? (i1 <= 0 ? -i1 / -i2 : -1 - ((i1 - 1) / -i2)) + : (i1 < 0 ? -1 - ((-1 - i1) / i2) : i1 / i2)); + + return make_int (i1); + } +#ifdef HAVE_BIGNUM + case BIGNUM_T: + if (bignum_sign (XBIGNUM_DATA (divisor)) == 0) + Fsignal (Qarith_error, Qnil); + bignum_floor (scratch_bignum, XBIGNUM_DATA (number), + XBIGNUM_DATA (divisor)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#endif + case FLOAT_T: + { + double f1 = extract_float (number); + double f2 = extract_float (divisor); + + if (f2 == 0.0) + Fsignal (Qarith_error, Qnil); + + IN_FLOAT2 (f1 = floor (f1 / f2), "floor", number, divisor); + return float_to_int (f1, "floor", number, divisor); + } +#ifdef HAVE_RATIO + case RATIO_T: + if (ratio_sign (XRATIO_DATA (divisor)) == 0) + Fsignal (Qarith_error, Qnil); + ratio_div (scratch_ratio, XRATIO_DATA (number), + XRATIO_DATA (divisor)); + bignum_floor (scratch_bignum, ratio_numerator (scratch_ratio), + ratio_denominator (scratch_ratio)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#endif +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + if (bigfloat_sign (XBIGFLOAT_DATA (divisor)) == 0) + Fsignal (Qarith_error, Qnil); + bigfloat_set_prec (scratch_bigfloat, + max (XBIGFLOAT_GET_PREC (number), + XBIGFLOAT_GET_PREC (divisor))); + bigfloat_div (scratch_bigfloat, XBIGFLOAT_DATA (number), + XBIGFLOAT_DATA (divisor)); + bigfloat_floor (scratch_bigfloat, scratch_bigfloat); + return make_bigfloat_bf (scratch_bigfloat); +#endif + } + } +#else /* !WITH_NUMBER_TYPES */ CHECK_INT_OR_FLOAT (number); if (! NILP (divisor)) @@ -787,6 +1029,7 @@ } return number; +#endif /* WITH_NUMBER_TYPES */ } DEFUN ("round", Fround, 1, 1, 0, /* @@ -802,9 +1045,51 @@ return (float_to_int (d, "round", number, Qunbound)); } +#ifdef HAVE_BIGNUM + if (INTEGERP (number)) +#else if (INTP (number)) +#endif return number; +#ifdef HAVE_RATIO + if (RATIOP (number)) + { + if (bignum_divisible_p (XRATIO_NUMERATOR (number), + XRATIO_DENOMINATOR (number))) + { + bignum_div (scratch_bignum, XRATIO_NUMERATOR (number), + XRATIO_DENOMINATOR (number)); + } + else + { + bignum_add (scratch_bignum2, XRATIO_NUMERATOR (number), + XRATIO_DENOMINATOR (number)); + bignum_div (scratch_bignum, scratch_bignum2, + XRATIO_DENOMINATOR (number)); + } + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } +#endif + +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (number)) + { + unsigned long prec = XBIGFLOAT_GET_PREC (number); + bigfloat_set_prec (scratch_bigfloat, prec); + bigfloat_set_prec (scratch_bigfloat2, prec); + bigfloat_set_double (scratch_bigfloat2, + bigfloat_sign (XBIGFLOAT_DATA (number)) * 0.5); + bigfloat_floor (scratch_bigfloat, scratch_bigfloat2); +#ifdef HAVE_BIGNUM + bignum_set_bigfloat (scratch_bignum, scratch_bigfloat); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#else + return make_int ((EMACS_INT) bigfloat_to_long (scratch_bigfloat)); +#endif /* HAVE_BIGNUM */ + } +#endif /* HAVE_BIGFLOAT */ + return Fround (wrong_type_argument (Qnumberp, number)); } @@ -817,9 +1102,36 @@ if (FLOATP (number)) return float_to_int (XFLOAT_DATA (number), "truncate", number, Qunbound); +#ifdef HAVE_BIGNUM + if (INTEGERP (number)) +#else if (INTP (number)) +#endif return number; +#ifdef HAVE_RATIO + if (RATIOP (number)) + { + bignum_div (scratch_bignum, XRATIO_NUMERATOR (number), + XRATIO_DENOMINATOR (number)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } +#endif + +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (number)) + { + bigfloat_set_prec (scratch_bigfloat, XBIGFLOAT_GET_PREC (number)); + bigfloat_trunc (scratch_bigfloat, XBIGFLOAT_DATA (number)); +#ifdef HAVE_BIGNUM + bignum_set_bigfloat (scratch_bignum, scratch_bigfloat); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); +#else + return make_int ((EMACS_INT) bigfloat_to_long (scratch_bigfloat)); +#endif /* HAVE_BIGNUM */ + } +#endif /* HAVE_BIGFLOAT */ + return Ftruncate (wrong_type_argument (Qnumberp, number)); }
--- a/src/fns.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/fns.c Mon Apr 05 22:50:11 2004 +0000 @@ -149,9 +149,9 @@ DEFUN ("random", Frandom, 0, 1, 0, /* Return a pseudo-random number. -All integers representable in Lisp are equally likely. - On most systems, this is 28 bits' worth. +All fixnums are equally likely. On most systems, this is 31 bits' worth. With positive integer argument N, return random number in interval [0,N). +N can be a bignum, in which case the range of possible values is extended. With argument t, set the random number seed from the current time and pid. */ (limit)) @@ -175,6 +175,13 @@ val = get_random () / denominator; while (val >= XINT (limit)); } +#ifdef HAVE_BIGNUM + else if (BIGNUMP (limit)) + { + bignum_random (scratch_bignum, XBIGNUM_DATA (limit)); + return Fcanonicalize_number (make_bignum_bg (scratch_bignum)); + } +#endif else val = get_random (); @@ -2840,8 +2847,33 @@ QUIT; if (EQ_WITH_EBOLA_NOTICE (obj1, obj2)) return 1; +#ifdef WITH_NUMBER_TYPES + if (NUMBERP (obj1) && NUMBERP (obj2)) + { + switch (promote_args (&obj1, &obj2)) + { + case FIXNUM_T: + return XREALINT (obj1) == XREALINT (obj2); +#ifdef HAVE_BIGNUM + case BIGNUM_T: + return bignum_eql (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2)); +#endif +#ifdef HAVE_RATIO + case RATIO_T: + return ratio_eql (XRATIO_DATA (obj1), XRATIO_DATA (obj2)); +#endif + case FLOAT_T: + return XFLOAT_DATA (obj1) == XFLOAT_DATA (obj2); +#ifdef HAVE_BIGFLOAT + case BIGFLOAT_T: + return bigfloat_eql (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2)); +#endif + } + } +#else if ((INTP (obj1) && FLOATP (obj2)) || (FLOATP (obj1) && INTP (obj2))) return extract_float (obj1) == extract_float (obj2); +#endif if (CHARP (obj1) && CHARP (obj2)) return DOWNCASE (0, XCHAR (obj1)) == DOWNCASE (0, XCHAR (obj2)); if (XTYPE (obj1) != XTYPE (obj2))
--- a/src/general-slots.h Mon Apr 05 21:50:47 2004 +0000 +++ b/src/general-slots.h Mon Apr 05 22:50:11 2004 +0000 @@ -57,6 +57,7 @@ SYMBOL (Qautodetect); SYMBOL (Qbad_variable); SYMBOL (Qbefore); +SYMBOL (Qbigfloat); SYMBOL (Qbinary); SYMBOL (Qbitmap); SYMBOL (Qboolean); @@ -127,6 +128,8 @@ SYMBOL (Qfile); SYMBOL_MODULE_API (Qfile_name); SYMBOL_KEYWORD (Q_filter); +SYMBOL (Qfixnum); +SYMBOL (Qfloat); SYMBOL (Qfont); SYMBOL (Qframe); SYMBOL (Qframes); @@ -232,6 +235,7 @@ SYMBOL (Qradio); SYMBOL (Qrassoc); SYMBOL (Qrassq); +SYMBOL (Qratio); SYMBOL (Qredisplay); SYMBOL (Qremove_all); SYMBOL (Qrequire);
--- a/src/lisp.h Mon Apr 05 21:50:47 2004 +0000 +++ b/src/lisp.h Mon Apr 05 22:50:11 2004 +0000 @@ -3377,6 +3377,14 @@ /************************************************************************/ /************************************************************************/ +/* Other numeric types */ +/************************************************************************/ +#ifdef WITH_NUMBER_TYPES +#include "number.h" +#endif + + +/************************************************************************/ /* prototypes */ /************************************************************************/ @@ -4333,6 +4341,9 @@ int locate_file (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object *, int); EXFUN (Flocate_file_clear_hashing, 1); int isfloat_string (const char *); +#ifdef HAVE_RATIO +int isratio_string (const char *); +#endif /* Well, I've decided to enable this. -- ben */ /* And I've decided to make it work right. -- sb */ @@ -5062,8 +5073,8 @@ extern Lisp_Object Qmalformed_property_list, Qmark, Qmodule; extern Lisp_Object Qmono_pixmap_image_instance_p, Qmouse_leave_buffer_hook; extern Lisp_Object Qnative_layout, Qnatnump, Qnetwork_error, Qno_catch; -extern Lisp_Object Qnothing_image_instance_p, Qnumber_char_or_marker_p; -extern Lisp_Object Qnumberp, Qout_of_memory; +extern Lisp_Object Qnonnegativep, Qnothing_image_instance_p; +extern Lisp_Object Qnumber_char_or_marker_p, Qnumberp, Qout_of_memory; extern Lisp_Object Qoverflow_error, Qpoint, Qpointer_glyph_p; extern Lisp_Object Qpointer_image_instance_p, Qprint_length; extern Lisp_Object Qprint_string_length, Qprinting_unreadable_object;
--- a/src/lread.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/lread.c Mon Apr 05 22:50:11 2004 +0000 @@ -1848,6 +1848,14 @@ #endif } } +#ifdef HAVE_RATIO + if (isratio_string (read_ptr)) + { + ratio_set_string (scratch_ratio, read_ptr, 0); + ratio_canonicalize (scratch_ratio); + return Fcanonicalize_number (make_ratio_rt (scratch_ratio)); + } +#endif if (isfloat_string (read_ptr)) return make_float (atof (read_ptr)); } @@ -1920,11 +1928,18 @@ return result; } overflow: +#ifdef HAVE_BIGNUM + { + bignum_set_string (scratch_bignum, buf, 0); + return make_bignum_bg (scratch_bignum); + } +#else return Fsignal (Qinvalid_read_syntax, list3 (build_msg_string ("Integer constant overflow in reader"), make_string (buf, len), make_int (base))); +#endif /* HAVE_BIGNUM */ loser: return Fsignal (Qinvalid_read_syntax, list3 (build_msg_string @@ -2653,6 +2668,39 @@ || state == (LEAD_INT|DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT) || state == (DOT_CHAR|TRAIL_INT|E_CHAR|EXP_INT))); } + +#ifdef HAVE_RATIO +int +isratio_string (const char *cp) +{ + /* Possible minus sign */ + if (*cp == '-') + cp++; + + /* Numerator */ + if (*cp < '0' || *cp > '9') + return 0; + + do { + cp++; + } while (*cp >= '0' && *cp <= '9'); + + /* Slash */ + if (*cp++ != '/') + return 0; + + /* Denominator */ + if (*cp < '0' || *cp > '9') + return 0; + + do { + cp++; + } while (*cp >= '0' && *cp <= '9'); + + return *cp == '\0' || *cp == ' ' || *cp =='\t' || *cp == '\n' || + *cp == '\r' || *cp == '\f'; +} +#endif static void * sequence_reader (Lisp_Object readcharfun,
--- a/src/lrecord.h Mon Apr 05 21:50:47 2004 +0000 +++ b/src/lrecord.h Mon Apr 05 22:50:11 2004 +0000 @@ -215,6 +215,9 @@ lrecord_type_emacs_gtk_boxed, lrecord_type_weak_box, lrecord_type_ephemeron, + lrecord_type_bignum, + lrecord_type_ratio, + lrecord_type_bigfloat, lrecord_type_free, /* only used for "free" lrecords */ lrecord_type_undefined, /* only used for debugging */ lrecord_type_last_built_in_type /* must be last */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/number-gmp.c Mon Apr 05 22:50:11 2004 +0000 @@ -0,0 +1,105 @@ +/* Numeric types for XEmacs using the GNU MP library. + Copyright (C) 2004 Jerry James. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +#include <config.h> +#include <limits.h> +#include <math.h> +#include "lisp.h" + +static mpf_t float_print_min, float_print_max; +gmp_randstate_t random_state; + +CIbyte * +bigfloat_to_string(mpf_t f, int base) +{ + mp_exp_t expt; + CIbyte *str = mpf_get_str (NULL, &expt, base, 0, f); + const int sign = mpf_sgn (f); + const int neg = (sign < 0) ? 1 : 0; + int len = strlen (str) + 1; /* Count the null terminator */ + + if (sign == 0 || (mpf_cmp (float_print_min, f) <= 0 && + mpf_cmp (f, float_print_max) <= 0)) + { + /* Move digits down to insert a radix point */ + if (expt <= 0) + { + /* We need room for a radix point and leading zeroes */ + const int space = -expt + 2; + XREALLOC_ARRAY (str, CIbyte, len + space); + memmove (&str[space + neg], &str[neg], len - neg); + memset (&str[neg], '0', space); + str[neg + 1] = '.'; + len += space; + } + else + { + /* We just need room for a radix point */ + XREALLOC_ARRAY (str, CIbyte, len + 1); + memmove (&str[expt + neg + 1], &str[expt + neg], len - (expt + neg)); + str[expt + neg] = '.'; + len++; + } + } + else + { + /* Computerized scientific notation */ + /* We need room for a radix point, format identifier, and exponent */ + const int space = (expt < 0) + ? (int)(log (-expt) / log (base)) + 3 + : (int)(log (expt) / log (base)) + 2; + XREALLOC_ARRAY (str, CIbyte, len + space); + memmove (&str[neg + 2], &str[neg + 1], len - neg); + str[len + 1] = 'l'; + sprintf (&str[len + 2], "%ld", expt); + } + return str; +} + +/* We need the next two functions since GNU MP insists on giving us an extra + parameter. */ +static void *gmp_realloc (void *ptr, size_t old_size /* unused */, + size_t new_size) +{ + return xrealloc (ptr, new_size); +} + +static void gmp_free (void *ptr, size_t size /* unused */) +{ + xfree (ptr, void *); +} + +void +init_number_gmp () +{ + mp_set_memory_functions ((void *(*) (size_t))xmalloc, gmp_realloc, gmp_free); + + /* The smallest number that is printed without exponents */ + mpf_init_set_d (float_print_min, 0.001); + + /* The largest number that is printed without exponents */ + mpf_init_set_ui (float_print_max, 10000000UL); + + /* Prepare the bignum/bigfloat random number generator */ + gmp_randinit_default (random_state); + gmp_randseed_ui (random_state, qxe_getpid () + time (NULL)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/number-gmp.h Mon Apr 05 22:50:11 2004 +0000 @@ -0,0 +1,227 @@ +/* Definitions of numeric types for XEmacs using the GNU MP library. + Copyright (C) 2004 Jerry James. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +/* This library defines the following types: + bignum = mpz_t + ratio = mpq_t + bigfloat = mpf_t +*/ + +#ifndef INCLUDED_number_gmp_h_ +#define INCLUDED_number_gmp_h_ + +#include <gmp.h> + +typedef mpz_t bignum; +typedef mpq_t ratio; +typedef mpf_t bigfloat; + +extern void init_number_gmp(void); + + +/********************************* Bignums **********************************/ + +#define HAVE_BIGNUM 1 + +extern gmp_randstate_t random_state; + +/***** Bignum: basic functions *****/ +#define bignum_init(b) mpz_init (b) +#define bignum_fini(b) mpz_clear (b) +#define bignum_hashcode(b) mpz_get_ui (b) +#define bignum_sign(b) mpz_sgn (b) +#define bignum_evenp(b) mpz_even_p (b) +#define bignum_oddp(b) mpz_odd_p (b) + +/***** Bignum: size *****/ +#define bignum_fits_int_p(b) mpz_fits_sint_p (b) +#define bignum_fits_uint_p(b) mpz_fits_uint_p (b) +#define bignum_fits_long_p(b) mpz_fits_slong_p (b) +#define bignum_fits_ulong_p(b) mpz_fits_ulong_p (b) + +/***** Bignum: conversions *****/ +#define bignum_to_string(b,base) mpz_get_str (NULL, base, b) +#define bignum_to_int(b) ((int) mpz_get_si (b)) +#define bignum_to_uint(b) ((unsigned int) mpz_get_ui (b)) +#define bignum_to_long(b) mpz_get_si (b) +#define bignum_to_ulong(b) mpz_get_ui (b) +#define bignum_to_double(b) mpz_get_d (b) + +/***** Bignum: converting assignments *****/ +#define bignum_set(b1,b2) mpz_set (b1, b2) +#define bignum_set_string(b,s,base) mpz_set_str (b, s, base) +#define bignum_set_long(b,l) mpz_set_si (b, l) +#define bignum_set_ulong(b,l) mpz_set_ui (b, l) +#define bignum_set_double(b,f) mpz_set_d (b, f) +#define bignum_set_ratio(b,r) mpz_set_q (b, r) +#define bignum_set_bigfloat(b,f) mpz_set_f (b, f) + +/***** Bignum: comparisons *****/ +#define bignum_cmp(b1,b2) mpz_cmp (b1, b2) +#define bignum_lt(b1,b2) (mpz_cmp (b1, b2) < 0) +#define bignum_le(b1,b2) (mpz_cmp (b1, b2) <= 0) +#define bignum_eql(b1,b2) (mpz_cmp (b1, b2) == 0) +#define bignum_ge(b1,b2) (mpz_cmp (b1, b2) >= 0) +#define bignum_gt(b1,b2) (mpz_cmp (b1, b2) > 0) + +/***** Bignum: arithmetic *****/ +#define bignum_neg(b,b2) mpz_neg (b, b2) +#define bignum_abs(b,b2) mpz_abs (b, b2) +#define bignum_add(b,b1,b2) mpz_add (b, b1, b2) +#define bignum_sub(b,b1,b2) mpz_sub (b, b1, b2) +#define bignum_mul(b,b1,b2) mpz_mul (b, b1, b2) +#define bignum_divisible_p(b1,b2) mpz_divisible_p (b1, b2) +#define bignum_div(b,b1,b2) mpz_tdiv_q (b, b1, b2) +#define bignum_ceil(b,b1,b2) mpz_cdiv_q (b, b1, b2) +#define bignum_floor(b,b1,b2) mpz_fdiv_q (b, b1, b2) +#define bignum_mod(b,b1,b2) mpz_mod (b, b1, b2) +#define bignum_pow(res,b,pow) mpz_pow_ui (res, b, pow) +#define bignum_gcd(res,b1,b2) mpz_gcd (res, b1, b2) +#define bignum_lcm(res,b1,b2) mpz_lcm (res, b1, b2) + +/***** Bignum: bit manipulations *****/ +#define bignum_and(res,b1,b2) mpz_and (res, b1, b2) +#define bignum_ior(res,b1,b2) mpz_ior (res, b1, b2) +#define bignum_xor(res,b1,b2) mpz_xor (res, b1, b2) +#define bignum_not(res,b) mpz_com (res, b) +#define bignum_setbit(b,bit) mpz_setbit (b, bit) +#define bignum_clrbit(b,bit) mpz_clrbit (b, bit) +#define bignum_testbit(b,bit) mpz_tstbit (b, bit) +#define bignum_lshift(res,b,bits) mpz_mul_2exp (res, b, bits) +#define bignum_rshift(res,b,bits) mpz_fdiv_q_2exp (res, b, bits) + +/***** Bignum: random numbers *****/ +#define bignum_random_seed(seed) gmp_randseed_ui (random_state, seed) +#define bignum_random(res,limit) mpz_urandomm (res, random_state, limit) + + +/********************************** Ratios **********************************/ + +#define HAVE_RATIO 1 + +/***** Ratio: basic functions *****/ +#define ratio_init(r) mpq_init (r) +#define ratio_fini(r) mpq_clear (r) +#define ratio_hashcode(r) \ + (mpz_get_ui (mpq_denref (r)) * mpz_get_ui (mpq_numref (r))) +#define ratio_sign(r) mpq_sgn (r) +#define ratio_numerator(r) mpq_numref (r) +#define ratio_denominator(r) mpq_denref (r) +#define ratio_canonicalize(r) mpq_canonicalize (r) + +/***** Ratio: conversions *****/ +#define ratio_to_string(r,base) mpq_get_str (NULL, base, r) +#define ratio_to_int(r) ((int) (mpq_get_d (r))) +#define ratio_to_uint(r) ((unsigned int) (mpq_get_d (r))) +#define ratio_to_long(r) ((long) (mpq_get_d (r))) +#define ratio_to_ulong(r) ((unsigned long) (mpq_get_d (r))) +#define ratio_to_double(r) mpq_get_d (r) + +/***** Ratio: converting assignments *****/ +#define ratio_set(r1,r2) mpq_set (r1, r2) +#define ratio_set_string(r,s,base) mpq_set_str (r, s, base) +#define ratio_set_long(r,l) mpq_set_si (r, l, 1UL) +#define ratio_set_ulong(r,l) mpq_set_ui (r, l, 1UL) +#define ratio_set_double(r,f) mpq_set_d (r, f) +#define ratio_set_bignum(r,b) mpq_set_z (r, b) +#define ratio_set_bigfloat(r,f) mpq_set_f (r, f) +#define ratio_set_long_ulong(r,num,den) mpq_set_si (r, num, den) +#define ratio_set_ulong_ulong(r,num,den) mpq_set_ui (r, num, den) +#define ratio_set_bignum_bignum(r,num,den) do { \ + mpz_set (mpq_numref (r), num); \ + mpz_set (mpq_denref (r), den); \ + mpq_canonicalize (r); \ + } while (0) + +/***** Ratio: comparisons *****/ +#define ratio_cmp(r1,r2) mpq_cmp (r1, r2) +#define ratio_lt(r1,r2) (mpq_cmp (r1, r2) < 0) +#define ratio_le(r1,r2) (mpq_cmp (r1, r2) <= 0) +#define ratio_eql(r1,r2) mpq_equal (r1, r2) +#define ratio_ge(r1,r2) (mpq_cmp (r1, r2) >= 0) +#define ratio_gt(r1,r2) (mpq_cmp (r1, r2) > 0) + +/***** Ratio: arithmetic *****/ +#define ratio_neg(q,q2) mpq_neg (q, q2) +#define ratio_abs(q,q2) mpq_abs (q, q2) +#define ratio_inv(q,q2) mpq_inv (q, q2) +#define ratio_add(res,q1,q2) mpq_add (res, q1, q2) +#define ratio_sub(res,q1,q2) mpq_sub (res, q1, q2) +#define ratio_mul(res,q1,q2) mpq_mul (res, q1, q2) +#define ratio_div(res,q1,q2) mpq_div (res, q1, q2) + + +/******************************** Bigfloats *********************************/ + +#define HAVE_BIGFLOAT 1 + +/***** Bigfloat: basic functions *****/ +#define bigfloat_init(f) mpf_init (f) +#define bigfloat_init_prec(f,prec) mpf_init2 (f, prec) +#define bigfloat_fini(f) mpf_clear (f) +#define bigfloat_hashcode(f) mpf_get_ui (f) +#define bigfloat_sign(f) mpf_sgn (f) +#define bigfloat_get_prec(f) mpf_get_prec (f) +#define bigfloat_set_prec(f, prec) mpf_set_prec (f, prec) +#define bigfloat_set_default_prec(prec) mpf_set_default_prec(prec) +#define bigfloat_get_default_prec() mpf_get_default_prec () + +/***** Bigfloat: conversions *****/ +extern CIbyte *bigfloat_to_string (bigfloat f, int base); +#define bigfloat_to_int(f) ((int) mpf_get_si (f)) +#define bigfloat_to_uint(f) ((unsigned int) mpf_get_ui (f)) +#define bigfloat_to_long(f) mpf_get_si (f) +#define bigfloat_to_ulong(f) mpf_get_ui (f) +#define bigfloat_to_double(f) mpf_get_d (f) + +/***** Bigfloat: converting assignments *****/ +#define bigfloat_set(f1,f2) mpf_set (f1, f2) +#define bigfloat_set_string(f,str,base) mpf_set_str (f, str, base) +#define bigfloat_set_long(f,l) mpf_set_si (f, l) +#define bigfloat_set_ulong(f,l) mpf_set_ui (f, l) +#define bigfloat_set_double(d,f) mpf_set_d (d, f) +#define bigfloat_set_bignum(f,b) mpf_set_z (f, b) +#define bigfloat_set_ratio(f,r) mpf_set_q (f, r) + +/***** Bigfloat: comparisons *****/ +#define bigfloat_cmp(f1,f2) mpf_cmp (f1, f2) +#define bigfloat_lt(f1,f2) (mpf_cmp (f1, f2) < 0) +#define bigfloat_le(f1,f2) (mpf_cmp (f1, f2) <= 0) +#define bigfloat_eql(f1,f2) (mpf_cmp (f1, f2) == 0) +#define bigfloat_eql_bits(f1,f2,bits) mpf_eq (f1, f2, bits) +#define bigfloat_ge(f1,f2) (mpf_cmp (f1, f2) >= 0) +#define bigfloat_gt(f1,f2) (mpf_cmp (f1, f2) > 0) + +/***** Bigfloat: arithmetic *****/ +#define bigfloat_neg(f,f2) mpf_neg (f, f2) +#define bigfloat_abs(f,f2) mpf_abs (f, f2) +#define bigfloat_add(res,f1,f2) mpf_add (res, f1, f2) +#define bigfloat_sub(res,f1,f2) mpf_sub (res, f1, f2) +#define bigfloat_mul(res,f1,f2) mpf_mul (res, f1, f2) +#define bigfloat_div(res,f1,f2) mpf_div (res, f1, f2) +#define bigfloat_ceil(res,f) mpf_ceil (res, f) +#define bigfloat_floor(res,f) mpf_floor (res, f) +#define bigfloat_trunc(res,f) mpf_trunc (res, f) +#define bigfloat_sqrt(res,f) mpf_sqrt (res, f) +#define bigfloat_pow(res,f,exp) mpf_pow_ui (res, f, exp) + +#endif /* INCLUDED_number_gmp_h_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/number-mp.c Mon Apr 05 22:50:11 2004 +0000 @@ -0,0 +1,509 @@ +/* Numeric types for XEmacs using the MP library. + Copyright (C) 2004 Jerry James. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +#include <config.h> +#include <limits.h> +#include <math.h> +#include "lisp.h" + +static MINT *bignum_bytesize, *bignum_long_sign_bit, *bignum_one, *bignum_two; +MINT *bignum_zero, *intern_bignum; +MINT *bignum_min_int, *bignum_max_int, *bignum_max_uint; +MINT *bignum_min_long, *bignum_max_long, *bignum_max_ulong; +short div_rem; + +char * +bignum_to_string (bignum b, int base) +{ + REGISTER unsigned int i; + unsigned int bufsize = 128U, index = 0U; + int sign; + char *buffer = xnew_array (char, 128), *retval; + MINT *quo = MP_ITOM (0); + short rem; + + /* FIXME: signal something if base is < 2 or doesn't fit into a short. */ + + /* Save the sign for later */ + sign = MP_MCMP (b, bignum_zero); + + if (sign == 0) + { + XREALLOC_ARRAY (buffer, char, 2); + buffer[0] = '0'; + buffer[1] = '\0'; + return buffer; + } + /* Copy abs(b) into quo for destructive modification */ + else if (sign < 0) + MP_MSUB (bignum_zero, b, quo); + else + MP_MOVE (b, quo); + + quo = MP_ITOM (0); + + /* Loop over the digits of b (in BASE) and place each one into buffer */ + for (i = 0U; MP_MCMP(quo, bignum_zero) > 0; i++) + { + MP_SDIV (quo, base, quo, &rem); + if (index == bufsize) + { + bufsize <<= 1; + XREALLOC_ARRAY (buffer, char, bufsize); + } + buffer[index++] = rem < 10 ? rem + '0' : rem - 10 + 'a'; + } + MP_MFREE (quo); + + /* Reverse the digits, maybe add a minus sign, and add a null terminator */ + bufsize = index + (sign < 0 ? 1 : 0) + 1; + retval = xnew_array (char, bufsize); + if (sign < 0) + { + retval[0] = '-'; + i = 1; + } + else + i = 0; + for (; i < bufsize - 1; i++) + retval[i] = buffer[--index]; + retval[bufsize - 1] = '\0'; + xfree (buffer, char *); + return retval; +} + +#define BIGNUM_TO_TYPE(type,accumtype) do { \ + MP_MULT (b, quo, quo); \ + for (i = 0U; i < sizeof(type); i++) \ + { \ + MP_SDIV (quo, 256, quo, &rem); \ + retval |= ((accumtype) rem) << (8 * i); \ + } \ + MP_MFREE (quo); \ +} while (0) + +int +bignum_to_int (bignum b) +{ + short rem, sign; + unsigned int retval = 0; + REGISTER unsigned int i; + MINT *quo; + + sign = MP_MCMP (b, bignum_zero) < 0 ? -1 : 1; + quo = MP_ITOM (sign); + BIGNUM_TO_TYPE (int, unsigned int); + return ((int) retval) * sign; +} + +unsigned int +bignum_to_uint (bignum b) +{ + short rem; + unsigned int retval = 0U; + REGISTER unsigned int i; + MINT *quo; + + quo = MP_ITOM (MP_MCMP (b, bignum_zero) < 0 ? -1 : 1); + BIGNUM_TO_TYPE (unsigned int, unsigned int); + return retval; +} + +long +bignum_to_long (bignum b) +{ + short rem, sign; + unsigned long retval = 0L; + REGISTER unsigned int i; + MINT *quo; + + sign = MP_MCMP (b, bignum_zero) < 0 ? -1 : 1; + quo = MP_ITOM (sign); + BIGNUM_TO_TYPE (long, unsigned long); + return ((long) retval) * sign; +} + +unsigned long +bignum_to_ulong (bignum b) +{ + short rem; + unsigned long retval = 0UL; + REGISTER unsigned int i; + MINT *quo; + + quo = MP_ITOM (MP_MCMP (b, bignum_zero) < 0 ? -1 : 1); + BIGNUM_TO_TYPE (unsigned long, unsigned long); + return retval; +} + +double +bignum_to_double (bignum b) +{ + short rem, sign; + double retval = 0.0; + REGISTER unsigned int i; + MINT *quo; + + sign = MP_MCMP (b, bignum_zero) < 0 ? -1 : 1; + quo = MP_ITOM (sign); + MP_MULT (b, quo, quo); + for (i = 0U; MP_MCMP(quo, bignum_zero) > 0; i++) + { + MP_SDIV (quo, 256, quo, &rem); + retval += rem * i * 256; + } + MP_MFREE (quo); + return retval * sign; +} + +static short +char_to_number (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + return -1; +} + +int +bignum_set_string (bignum b, const char *s, int base) +{ + MINT *mbase; + short digit; + + if (base == 0) + { + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + { + base = 16; + s += 2; + } + else if (*s == '0') + { + base = 8; + s++; + } + else + base = 10; + } + + /* FIXME: signal something if base is < 2 or doesn't fit into a short. */ + + mbase = MP_ITOM ((short) base); + MP_MOVE (bignum_zero, b); + + for (digit = char_to_number (*s); digit >= 0 && digit < base; + digit = char_to_number (*++s)) + { + MINT *temp; + + MP_MULT (b, mbase, b); + temp = MP_ITOM (digit); + MP_MADD (b, temp, b); + MP_MFREE (temp); + } + + return (digit >= 0) ? -1 : 0; +} + +void +bignum_set_long (MINT *b, long l) +{ + /* Negative l is hard, not least because -LONG_MIN == LONG_MIN. We pretend + that l is unsigned, then subtract off the amount equal to the sign bit. */ + bignum_set_ulong (b, (unsigned long) l); + if (l < 0L) + MP_MSUB (b, bignum_long_sign_bit, b); +} + +void +bignum_set_ulong (bignum b, unsigned long l) +{ + REGISTER unsigned int i; + MINT *multiplier = MP_ITOM (1); + + MP_MOVE (bignum_zero, b); + for (i = 0UL; l > 0UL; l >>= 8, i++) + { + MINT *temp = MP_ITOM ((short) (l & 255)); + MP_MULT (multiplier, temp, temp); + MP_MADD (b, temp, b); + MP_MULT (multiplier, bignum_bytesize, multiplier); + MP_MFREE (temp); + } + MP_MFREE (multiplier); +} + +void +bignum_set_double (bignum b, double d) +{ + REGISTER unsigned int i; + int negative = (d < 0) ? 1 : 0; + MINT *multiplier = MP_ITOM (1); + + MP_MOVE (bignum_zero, b); + if (negative) + d = -d; + for (i = 0UL; d > 0.0; d /= 256, i++) + { + MINT *temp = MP_ITOM ((short) fmod (d, 256.0)); + MP_MULT (multiplier, temp, temp); + MP_MADD (b, temp, b); + MP_MULT (multiplier, bignum_bytesize, multiplier); + MP_MFREE (temp); + } + MP_MFREE (multiplier); + if (negative) + MP_MSUB (bignum_zero, b, b); +} + +/* Return nonzero if b1 is exactly divisible by b2 */ +int +bignum_divisible_p (bignum b1, bignum b2) +{ + int retval; + MINT *rem = MP_ITOM (0); + MP_MDIV (b1, b2, intern_bignum, rem); + retval = (MP_MCMP (rem, bignum_zero) == 0); + MP_MFREE (rem); + return retval; +} + +void bignum_ceil (bignum quotient, bignum N, bignum D) +{ + MP_MDIV (N, D, quotient, intern_bignum); + if (MP_MCMP (intern_bignum, bignum_zero) > 0 && + MP_MCMP (quotient, bignum_zero) > 0) + MP_MADD (quotient, bignum_one, quotient); +} + +void bignum_floor (bignum quotient, bignum N, bignum D) +{ + MP_MDIV (N, D, quotient, intern_bignum); + if (MP_MCMP (intern_bignum, bignum_zero) > 0 && + MP_MCMP (quotient, bignum_zero) < 0) + MP_MSUB (quotient, bignum_one, quotient); +} + +/* RESULT = N to the POWth power */ +void +bignum_pow (bignum result, bignum n, unsigned long pow) +{ + MP_MOVE (bignum_one, result); + for ( ; pow > 0UL; pow--) + MP_MULT (result, n, result); +} + +/* lcm(b1,b2) = b1 * b2 / gcd(b1, b2) */ +void +bignum_lcm (bignum result, bignum b1, bignum b2) +{ + MP_MULT (b1, b2, result); + MP_GCD (b1, b2, intern_bignum); + MP_MDIV (result, intern_bignum, result, intern_bignum); +} + +/* FIXME: We can't handle negative args, so right now we just make them + positive before doing anything else. How should we really handle negative + args? */ +#define bignum_bit_op(result, b1, b2, op) \ + REGISTER unsigned int i; \ + MINT *multiplier = MP_ITOM (1), *n1 = MP_ITOM (0), *n2 = MP_ITOM (0); \ + \ + if (MP_MCMP (bignum_zero, b1) > 0) \ + MP_MSUB (bignum_zero, b1, n1); \ + else \ + MP_MOVE (b1, n1); \ + if (MP_MCMP (bignum_zero, b2) > 0) \ + MP_MSUB (bignum_zero, b2, n2); \ + else \ + MP_MOVE (b2, n2); \ + \ + MP_MOVE (bignum_zero, result); \ + \ + for (i = 0UL; MP_MCMP (bignum_zero, n1) < 0 && \ + MP_MCMP (bignum_zero, n2) < 0; i++) \ + { \ + short byte1, byte2; \ + MINT *temp; \ + \ + MP_SDIV (n1, 256, n1, &byte1); \ + MP_SDIV (n2, 256, n2, &byte2); \ + temp = MP_ITOM (byte1 op byte2); \ + MP_MULT (multiplier, temp, temp); \ + MP_MADD (result, temp, result); \ + MP_MULT (multiplier, bignum_bytesize, multiplier); \ + MP_MFREE (temp); \ + } \ + MP_MFREE (n2); \ + MP_MFREE (n1); \ + MP_MFREE (multiplier) + +void +bignum_and (bignum result, bignum b1, bignum b2) +{ + bignum_bit_op (result, b1, b2, &); +} + +void +bignum_ior (bignum result, bignum b1, bignum b2) +{ + bignum_bit_op (result, b1, b2, |); +} + +void +bignum_xor (bignum result, bignum b1, bignum b2) +{ + bignum_bit_op (result, b1, b2, ^); +} + +/* NOT is not well-defined for bignums ... where do you stop flipping bits? + We just flip until we see the last one. This is probably a bad idea. */ +void +bignum_not (bignum result, bignum b) +{ + REGISTER unsigned int i; + MINT *multiplier = MP_ITOM (1), *n = MP_ITOM (0); + + if (MP_MCMP (bignum_zero, b) > 0) + MP_MSUB (bignum_zero, b, n); + else + MP_MOVE (b, n); + + MP_MOVE (bignum_zero, result); + + for (i = 0UL; MP_MCMP (bignum_zero, n) < 0; i++) + { + short byte; + MINT *temp; + + MP_SDIV (n, 256, n, &byte); + temp = MP_ITOM (~byte); + MP_MULT (multiplier, temp, temp); + MP_MADD (result, temp, result); + MP_MULT (multiplier, bignum_bytesize, multiplier); + MP_MFREE (temp); + } + MP_MFREE (n); + MP_MFREE (multiplier); +} + +void +bignum_setbit (bignum b, unsigned long bit) +{ + bignum_pow (intern_bignum, bignum_two, bit); + bignum_ior (b, b, intern_bignum); +} + +/* This is so evil, even I feel queasy. */ +void +bignum_clrbit (bignum b, unsigned long bit) +{ + MINT *num = MP_ITOM (0); + + /* See if the bit is already set, and subtract it off if not */ + MP_MOVE (b, intern_bignum); + bignum_pow (num, bignum_two, bit); + bignum_ior (intern_bignum, intern_bignum, num); + if (MP_MCMP (b, intern_bignum) == 0) + MP_MSUB (b, num, b); + MP_MFREE (num); +} + +int +bignum_testbit (bignum b, unsigned long bit) +{ + bignum_pow (intern_bignum, bignum_two, bit); + bignum_and (intern_bignum, b, intern_bignum); + return MP_MCMP (intern_bignum, bignum_zero); +} + +void +bignum_lshift (bignum result, bignum b, unsigned long bits) +{ + bignum_pow (intern_bignum, bignum_two, bits); + MP_MULT (b, intern_bignum, result); +} + +void +bignum_rshift (bignum result, bignum b, unsigned long bits) +{ + bignum_pow (intern_bignum, bignum_two, bits); + MP_MDIV (b, intern_bignum, result, intern_bignum); +} + +void bignum_random_seed(unsigned long seed) +{ + /* FIXME: Implement me */ +} + +void bignum_random(bignum result, bignum limit) +{ + /* FIXME: Implement me */ + MP_MOVE (bignum_zero, result); +} + +void +init_number_mp () +{ + REGISTER unsigned int i; + + bignum_zero = MP_ITOM (0); + bignum_one = MP_ITOM (1); + bignum_two = MP_ITOM (2); + + /* intern_bignum holds throwaway values from macro expansions in + number-mp.h. Its value is immaterial. */ + intern_bignum = MP_ITOM (0); + + /* bignum_bytesize holds the number of bits in a byte. */ + bignum_bytesize = MP_ITOM (256); + + /* bignum_long_sign_bit holds an adjustment for negative longs. */ + bignum_long_sign_bit = MP_ITOM (256); + for (i = 1UL; i < sizeof (long); i++) + MP_MULT (bignum_bytesize, bignum_long_sign_bit, bignum_long_sign_bit); + + /* The MP interface only supports turning short ints into MINTs, so we have + to set these the hard way. */ + + bignum_min_int = MP_ITOM (0); + bignum_set_long (bignum_min_int, INT_MIN); + + bignum_max_int = MP_ITOM (0); + bignum_set_long (bignum_max_int, INT_MAX); + + bignum_max_uint = MP_ITOM (0); + bignum_set_ulong (bignum_max_uint, UINT_MAX); + + bignum_min_long = MP_ITOM (0); + bignum_set_long (bignum_min_long, LONG_MIN); + + bignum_max_long = MP_ITOM (0); + bignum_set_long (bignum_max_long, LONG_MAX); + + bignum_max_ulong = MP_ITOM (0); + bignum_set_ulong (bignum_max_ulong, ULONG_MAX); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/number-mp.h Mon Apr 05 22:50:11 2004 +0000 @@ -0,0 +1,161 @@ +/* Definitions of numeric types for XEmacs using the MP library. + Copyright (C) 2004 Jerry James. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +/* This library defines the following types: + bignum = MINT + + The MP library does not include support for ratios or bigfloats. +*/ + +#ifndef INCLUDED_number_mp_h_ +#define INCLUDED_number_mp_h_ + +/* BSD MP libraries without MP_PREFIX define a function named pow in mp.h that + has a different prototype from the one in math.h. We don't use that + function anyway, so we do this for safety purposes. However, this means + that number-mp.h must always be included before math.h. */ +#define pow mp_pow +#include <mp.h> +#undef pow + +#ifdef MP_PREFIX +#define MP_GCD mp_gcd +#define MP_ITOM mp_itom +#define MP_MADD mp_madd +#define MP_MCMP mp_mcmp +#define MP_MDIV mp_mdiv +#define MP_MFREE mp_mfree +#define MP_MSUB mp_msub +#define MP_MULT mp_mult +#define MP_SDIV mp_sdiv +#ifdef HAVE_MP_MOVE +#define MP_MOVE(x,y) mp_move (x, y) +#else +#define MP_MOVE(x,y) mp_madd (x, bignum_zero, y) +#endif +#else +#define MP_GCD gcd +#define MP_ITOM itom +#define MP_MADD madd +#define MP_MCMP mcmp +#define MP_MDIV mdiv +#define MP_MFREE mfree +#define MP_MSUB msub +#define MP_MULT mult +#define MP_SDIV sdiv +#ifdef HAVE_MP_MOVE +#define MP_MOVE(x,y) move (x, y) +#else +#define MP_MOVE(x,y) madd (x, bignum_zero, y) +#endif +#endif + +typedef MINT *bignum; + +extern void init_number_mp(void); + + +/********************************* Bignums **********************************/ + +#define HAVE_BIGNUM 1 + +extern MINT *bignum_zero, *intern_bignum; +extern MINT *bignum_min_int, *bignum_max_int, *bignum_max_uint; +extern MINT *bignum_min_long, *bignum_max_long, *bignum_max_ulong; +extern short div_rem; + +/***** Bignum: basic functions *****/ +#define bignum_init(b) (b = MP_ITOM (0)) +#define bignum_fini(b) MP_MFREE (b) +#define bignum_hashcode(b) bignum_to_uint (b) +#define bignum_sign(b) MP_MCMP (b, bignum_zero) +#define bignum_evenp(b) (MP_SDIV (b, 2, intern_bignum, &div_rem), \ + div_rem == 0) +#define bignum_oddp(b) (MP_SDIV (b, 2, intern_bignum, &div_rem), \ + div_rem != 0) + +/***** Bignum: size *****/ +#define bignum_fits_int_p(b) (MP_MCMP (b, bignum_min_int) >= 0 && \ + MP_MCMP (b, bignum_max_int) <= 0) +#define bignum_fits_uint_p(b) (MP_MCMP (b, bignum_zero) >= 0 && \ + MP_MCMP (b, bignum_max_uint) <= 0) +#define bignum_fits_long_p(b) (MP_MCMP (b, bignum_min_long) >= 0 && \ + MP_MCMP (b, bignum_max_long) <= 0) +#define bignum_fits_ulong_p(b) (MP_MCMP (b, bignum_zero) >= 0 && \ + MP_MCMP (b, bignum_max_ulong) <= 0) + +/***** Bignum: conversions *****/ +extern char *bignum_to_string(bignum, int); +extern int bignum_to_int(bignum); +extern unsigned int bignum_to_uint(bignum); +extern long bignum_to_long(bignum); +extern unsigned long bignum_to_ulong(bignum); +extern double bignum_to_double(bignum); + +/***** Bignum: converting assignments *****/ +#define bignum_set(b1, b2) MP_MOVE (b2, b1) +extern int bignum_set_string(bignum, const char *, int); +extern void bignum_set_long(bignum, long); +extern void bignum_set_ulong(bignum, unsigned long); +extern void bignum_set_double(bignum, double); + +/***** Bignum: comparisons *****/ +#define bignum_cmp(b1,b2) MP_MCMP (b1, b2) +#define bignum_lt(b1,b2) (MP_MCMP (b1, b2) < 0) +#define bignum_le(b1,b2) (MP_MCMP (b1, b2) <= 0) +#define bignum_eql(b1,b2) (MP_MCMP (b1, b2) == 0) +#define bignum_ge(b1,b2) (MP_MCMP (b1, b2) >= 0) +#define bignum_gt(b1,b2) (MP_MCMP (b1, b2) > 0) + +/***** Bignum: arithmetic *****/ +#define bignum_neg(b,b2) MP_MSUB (bignum_zero, b2, b) +#define bignum_abs(b,b2) (MP_MCMP (b2, bignum_zero) < 0 \ + ? MP_MSUB (bignum_zero, b2, b) \ + : MP_MADD (bignum_zero, b2, b)) +#define bignum_add(b,b1,b2) MP_MADD (b1, b2, b) +#define bignum_sub(b,b1,b2) MP_MSUB (b1, b2, b) +#define bignum_mul(b,b1,b2) MP_MULT (b1, b2, b) +extern int bignum_divisible_p(bignum, bignum); +#define bignum_div(b,b1,b2) MP_MDIV (b1, b2, b, intern_bignum) +extern void bignum_ceil(bignum, bignum, bignum); +extern void bignum_floor(bignum, bignum, bignum); +#define bignum_mod(b,b1,b2) MP_MDIV (b1, b2, intern_bignum, b) +extern void bignum_pow(bignum, bignum, unsigned long); +#define bignum_gcd(res,b1,b2) MP_GCD (b1, b2, res) +extern void bignum_lcm(bignum, bignum, bignum); + +/***** Bignum: bit manipulations *****/ +extern void bignum_and(bignum, bignum, bignum); +extern void bignum_ior(bignum, bignum, bignum); +extern void bignum_xor(bignum, bignum, bignum); +extern void bignum_not(bignum, bignum); +extern void bignum_setbit(bignum, unsigned long); +extern void bignum_clrbit(bignum, unsigned long); +extern int bignum_testbit(bignum, unsigned long); +extern void bignum_lshift(bignum, bignum, unsigned long); +extern void bignum_rshift(bignum, bignum, unsigned long); + +/***** Bignum: random numbers *****/ +extern void bignum_random_seed(unsigned long); +extern void bignum_random(bignum, bignum); + +#endif /* INCLUDED_number_mp_h_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/number.c Mon Apr 05 22:50:11 2004 +0000 @@ -0,0 +1,812 @@ +/* Numeric types for XEmacs. + Copyright (C) 2004 Jerry James. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +#include <config.h> +#include <limits.h> +#include "lisp.h" + +Lisp_Object Qintegerp, Qrationalp, Qfloatingp, Qrealp, Qnumberp; +Lisp_Object Vdefault_float_precision; +Fixnum Vmost_negative_fixnum, Vmost_positive_fixnum; +static Lisp_Object Qunsupported_type; +static Lisp_Object Vbigfloat_max_prec; +static int number_initialized; + +#ifdef HAVE_BIGNUM +bignum scratch_bignum, scratch_bignum2; +#endif +#ifdef HAVE_RATIO +ratio scratch_ratio; +#endif +#ifdef HAVE_BIGFLOAT +bigfloat scratch_bigfloat, scratch_bigfloat2; +#endif + +/********************************* Bignums **********************************/ +#ifdef HAVE_BIGNUM +static void +bignum_print (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) +{ + CIbyte *bstr = bignum_to_string (XBIGNUM_DATA (obj), 10); + write_c_string (printcharfun, bstr); + xfree (bstr, CIbyte *); +} + +static void +bignum_finalize (void *header, int for_disksave) +{ + if (for_disksave) + invalid_operation ("Can't dump an XEmacs containing bignum objects", + VOID_TO_LISP (header)); + bignum_fini (((Lisp_Bignum *)header)->data); +} + +static int +bignum_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) +{ + return bignum_eql (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2)); +} + +static Hashcode +bignum_hash (Lisp_Object obj, int depth) +{ + return bignum_hashcode (XBIGNUM_DATA (obj)); +} + +static const struct memory_description bignum_description[] = { + { XD_OPAQUE_PTR, offsetof (Lisp_Bignum, data) }, + { XD_END } +}; + +DEFINE_LRECORD_IMPLEMENTATION ("bignum", bignum, 0, 0, + bignum_print, bignum_finalize, bignum_equal, + bignum_hash, bignum_description, Lisp_Bignum); + +Lisp_Object +string_to_bignum(const Ibyte *str, Bytecount len, int base) +{ + Lisp_Object b = make_bignum (0L); + return (bignum_set_string (XBIGNUM_DATA (b), str, base) < 0) + ? Fsignal (Qinvalid_read_syntax, + list3 (build_msg_string + ("Invalid integer constant in reader"), + make_string (str, len), + make_int (10))) + : b; +} + +#else /* !HAVE_BIGNUM */ + +Lisp_Object Qbignump; + +#endif /* HAVE_BIGNUM */ + +DEFUN ("bignump", Fbignump, 1, 1, 0, /* +Return t if OBJECT is a bignum, nil otherwise. +*/ + (object)) +{ + return BIGNUMP (object) ? Qt : Qnil; +} + + +/********************************* Integers *********************************/ +DEFUN ("integerp", Fintegerp, 1, 1, 0, /* +Return t if OBJECT is an integer, nil otherwise. +*/ + (object)) +{ + return INTEGERP (object) ? Qt : Qnil; +} + +DEFUN ("evenp", Fevenp, 1, 1, 0, /* +Return t if INTEGER is even, nil otherwise. +*/ + (integer)) +{ + CONCHECK_INTEGER (integer); + return BIGNUMP (integer) + ? bignum_evenp (XBIGNUM_DATA (integer)) + : XTYPE (integer) == Lisp_Type_Int_Even; +} + +DEFUN ("odd", Foddp, 1, 1, 0, /* +Return t if INTEGER is odd, nil otherwise. +*/ + (integer)) +{ + CONCHECK_INTEGER (integer); + return BIGNUMP (integer) + ? bignum_oddp (XBIGNUM_DATA (integer)) + : XTYPE (integer) == Lisp_Type_Int_Odd; +} + + +/********************************** Ratios **********************************/ +#ifdef HAVE_RATIO +static void +ratio_print (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) +{ + CIbyte *rstr = ratio_to_string (XRATIO_DATA (obj), 10); + write_c_string (printcharfun, rstr); + xfree (rstr, CIbyte *); +} + +static void +ratio_finalize (void *header, int for_disksave) +{ + if (for_disksave) + invalid_operation ("Can't dump an XEmacs containing ratio objects", + VOID_TO_LISP (header)); + ratio_fini (((Lisp_Ratio *)header)->data); +} +; + +static int +ratio_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) +{ + return ratio_eql (XRATIO_DATA (obj1), XRATIO_DATA (obj2)); +} + +static Hashcode +ratio_hash (Lisp_Object obj, int depth) +{ + return ratio_hashcode (XRATIO_DATA (obj)); +} + +static const struct memory_description ratio_description[] = { + { XD_OPAQUE_PTR, offsetof (Lisp_Ratio, data) }, + { XD_END } +}; + +DEFINE_LRECORD_IMPLEMENTATION ("ratio", ratio, 0, 0, + ratio_print, ratio_finalize, ratio_equal, + ratio_hash, ratio_description, Lisp_Ratio); + +#else /* !HAVE_RATIO */ + +Lisp_Object Qratiop; + +#endif /* HAVE_RATIO */ + +DEFUN ("ratiop", Fratiop, 1, 1, 0, /* +Return t if OBJECT is a ratio, nil otherwise. +*/ + (object)) +{ + return RATIOP (object) ? Qt : Qnil; +} + + +/******************************** Rationals *********************************/ +DEFUN ("rationalp", Frationalp, 1, 1, 0, /* +Return t if OBJECT is a rational, nil otherwise. +*/ + (object)) +{ + return RATIONALP (object) ? Qt : Qnil; +} + +DEFUN ("numerator", Fnumerator, 1, 1, 0, /* +Return the numerator of the canonical form of RATIONAL. +If RATIONAL is an integer, RATIONAL is returned. +*/ + (rational)) +{ + CONCHECK_RATIONAL (rational); +#ifdef HAVE_RATIO + return RATIOP (rational) + ? make_bignum_bg (XRATIO_NUMERATOR (rational)) + : rational; +#else + return rational; +#endif +} + +DEFUN ("denominator", Fdenominator, 1, 1, 0, /* +Return the denominator of the canonical form of RATIONAL. +If RATIONAL is an integer, 1 is returned. +*/ + (rational)) +{ + CONCHECK_RATIONAL (rational); +#ifdef HAVE_RATIO + return RATIOP (rational) + ? make_bignum_bg (XRATIO_DENOMINATOR (rational)) + : make_int (1); +#else + return rational; +#endif +} + + +/******************************** Bigfloats *********************************/ +#ifdef HAVE_BIGFLOAT +static void +bigfloat_print (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) +{ + CIbyte *fstr = bigfloat_to_string (XBIGFLOAT_DATA (obj), 10); + write_c_string (printcharfun, fstr); + xfree (fstr, CIbyte *); +} + +static void +bigfloat_finalize (void *header, int for_disksave) +{ + if (for_disksave) + invalid_operation ("Can't dump an XEmacs containing bigfloat objects", + VOID_TO_LISP (header)); + bigfloat_fini (((Lisp_Bigfloat *)header)->bf); +} + +static int +bigfloat_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) +{ + return bigfloat_eql (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2)); +} + +static Hashcode +bigfloat_hash (Lisp_Object obj, int depth) +{ + return bigfloat_hashcode (XBIGFLOAT_DATA (obj)); +} + +static const struct memory_description bigfloat_description[] = { + { XD_OPAQUE_PTR, offsetof (Lisp_Bigfloat, bf) }, + { XD_END } +}; + +DEFINE_LRECORD_IMPLEMENTATION ("bigfloat", bigfloat, 1, 0, + bigfloat_print, bigfloat_finalize, + bigfloat_equal, bigfloat_hash, + bigfloat_description, Lisp_Bigfloat); + +#else /* !HAVE_BIGFLOAT */ + +Lisp_Object Qbigfloatp; + +#endif /* HAVE_BIGFLOAT */ + +DEFUN ("bigfloatp", Fbigfloatp, 1, 1, 0, /* +Return t if OBJECT is a bigfloat, nil otherwise. +*/ + (object)) +{ + return BIGFLOATP (object) ? Qt : Qnil; +} + +static int +default_float_precision_changed (Lisp_Object sym, Lisp_Object *val, + Lisp_Object in_object, int flags) +{ + unsigned long prec; + + CONCHECK_INTEGER (*val); +#ifdef HAVE_BIGFLOAT + if (INTP (*val)) + prec = XINT (*val); + else + { + if (!bignum_fits_ulong_p (XBIGNUM_DATA (*val))) + args_out_of_range_3 (*val, Qzero, Vbigfloat_max_prec); + prec = bignum_to_ulong (XBIGNUM_DATA (*val)); + } + if (prec != 0UL) + bigfloat_set_default_prec (prec); +#endif + return 0; +} + + +/********************************* Floating *********************************/ +Lisp_Object +make_floating (double d) +{ +#ifdef HAVE_BIGFLOAT + if (ZEROP (Vdefault_float_precision)) +#endif + return make_float (d); +#ifdef HAVE_BIGFLOAT + else + return make_bigfloat (d, 0UL); +#endif +} + +DEFUN ("floatingp", Ffloatingp, 1, 1, 0, /* +Return t if OBJECT is a floating point number of any kind, nil otherwise. +*/ + (object)) +{ + return FLOATINGP (object) ? Qt : Qnil; +} + + +/********************************** Reals ***********************************/ +DEFUN ("realp", Frealp, 1, 1, 0, /* +Return t if OBJECT is a real, nil otherwise. +*/ + (object)) +{ + return REALP (object) ? Qt : Qnil; +} + + +/********************************* Numbers **********************************/ +DEFUN ("canonicalize-number", Fcanonicalize_number, 1, 1, 0, /* +Return the canonical form of NUMBER. +*/ + (number)) +{ + /* The tests should go in order from larger, more expressive, or more + complex types to smaller, less expressive, or simpler types so that a + number can cascade all the way down to the simplest type if + appropriate. */ +#ifdef HAVE_RATIO + if (RATIOP (number) && + bignum_fits_long_p (XRATIO_DENOMINATOR (number)) && + bignum_to_long (XRATIO_DENOMINATOR (number)) == 1L) + number = make_bignum_bg (XRATIO_NUMERATOR (number)); +#endif +#ifdef HAVE_BIGNUM + if (BIGNUMP (number) && bignum_fits_int_p (XBIGNUM_DATA (number))) + { + int n = bignum_to_int (XBIGNUM_DATA (number)); + if (NUMBER_FITS_IN_AN_EMACS_INT (n)) + number = make_int (n); + } +#endif + return number; +} + +enum number_type +get_number_type (Lisp_Object arg) +{ + if (INTP (arg)) + return FIXNUM_T; +#ifdef HAVE_BIGNUM + if (BIGNUMP (arg)) + return BIGNUM_T; +#endif +#ifdef HAVE_RATIO + if (RATIOP (arg)) + return RATIO_T; +#endif + if (FLOATP (arg)) + return FLOAT_T; +#ifdef HAVE_BIGFLOAT + if (BIGFLOATP (arg)) + return BIGFLOAT_T; +#endif + /* Catch unintentional bad uses of this function */ + abort (); +} + +/* Convert NUMBER to type TYPE. If TYPE is BIGFLOAT_T then use the indicated + PRECISION; otherwise, PRECISION is ignored. */ +static Lisp_Object +internal_coerce_number (Lisp_Object number, enum number_type type, + unsigned long precision) +{ + enum number_type current_type; + + if (CHARP (number)) + number = make_int (XCHAR (number)); + else if (MARKERP (number)) + number = make_int (marker_position (number)); + + /* Note that CHECK_NUMBER ensures that NUMBER is a supported type. Hence, + we abort() in the #else sections below, because it shouldn't be possible + to arrive there. */ + CHECK_NUMBER (number); + current_type = get_number_type (number); + switch (current_type) + { + case FIXNUM_T: + switch (type) + { + case FIXNUM_T: + return number; + case BIGNUM_T: +#ifdef HAVE_BIGNUM + return make_bignum (XREALINT (number)); +#else + abort (); +#endif /* HAVE_BIGNUM */ + case RATIO_T: +#ifdef HAVE_RATIO + return make_ratio (XREALINT (number), 1UL); +#else + abort (); +#endif /* HAVE_RATIO */ + case FLOAT_T: + return make_float (XREALINT (number)); + case BIGFLOAT_T: +#ifdef HAVE_BIGFLOAT + return make_bigfloat (XREALINT (number), precision); +#else + abort (); +#endif /* HAVE_BIGFLOAT */ + } + case BIGNUM_T: +#ifdef HAVE_BIGNUM + switch (type) + { + case FIXNUM_T: + return make_int (bignum_to_long (XBIGNUM_DATA (number))); + case BIGNUM_T: + return number; + case RATIO_T: +#ifdef HAVE_RATIO + bignum_set_long (scratch_bignum, 1L); + return make_ratio_bg (XBIGNUM_DATA (number), scratch_bignum); +#else + abort (); +#endif /* HAVE_RATIO */ + case FLOAT_T: + return make_float (bignum_to_double (XBIGNUM_DATA (number))); + case BIGFLOAT_T: +#ifdef HAVE_BIGFLOAT + { + Lisp_Object temp; + temp = make_bigfloat (0.0, precision); + bigfloat_set_bignum (XBIGFLOAT_DATA (temp), XBIGNUM_DATA (number)); + return temp; + } +#else + abort (); +#endif /* HAVE_BIGFLOAT */ + } +#else + abort (); +#endif /* HAVE_BIGNUM */ + case RATIO_T: +#ifdef HAVE_RATIO + switch (type) + { + case FIXNUM_T: + bignum_div (scratch_bignum, XRATIO_NUMERATOR (number), + XRATIO_DENOMINATOR (number)); + return make_int (bignum_to_long (scratch_bignum)); + case BIGNUM_T: + bignum_div (scratch_bignum, XRATIO_NUMERATOR (number), + XRATIO_DENOMINATOR (number)); + return make_bignum_bg (scratch_bignum); + case RATIO_T: + return number; + case FLOAT_T: + return make_float (ratio_to_double (XRATIO_DATA (number))); + case BIGFLOAT_T: +#ifdef HAVE_BIGFLOAT + { + Lisp_Object temp; + temp = make_bigfloat (0.0, precision); + bigfloat_set_ratio (XBIGFLOAT_DATA (temp), XRATIO_DATA (number)); + return temp; + } +#else + abort (); +#endif /* HAVE_BIGFLOAT */ + } +#else + abort (); +#endif /* HAVE_RATIO */ + case FLOAT_T: + switch (type) + { + case FIXNUM_T: + return Fround (number); + case BIGNUM_T: +#ifdef HAVE_BIGNUM + bignum_set_double (scratch_bignum, XFLOAT_DATA (number)); + return make_bignum_bg (scratch_bignum); +#else + abort (); +#endif /* HAVE_BIGNUM */ + case RATIO_T: +#ifdef HAVE_RATIO + ratio_set_double (scratch_ratio, XFLOAT_DATA (number)); + return make_ratio_rt (scratch_ratio); +#else + abort (); +#endif /* HAVE_RATIO */ + case FLOAT_T: + return number; + case BIGFLOAT_T: +#ifdef HAVE_BIGFLOAT + bigfloat_set_prec (scratch_bigfloat, precision); + bigfloat_set_double (scratch_bigfloat, XFLOAT_DATA (number)); + return make_bigfloat_bf (scratch_bigfloat); +#else + abort (); +#endif /* HAVE_BIGFLOAT */ + } + case BIGFLOAT_T: +#ifdef HAVE_BIGFLOAT + switch (type) + { + case FIXNUM_T: + return make_int (bigfloat_to_long (XBIGFLOAT_DATA (number))); + case BIGNUM_T: +#ifdef HAVE_BIGNUM + bignum_set_bigfloat (scratch_bignum, XBIGFLOAT_DATA (number)); + return make_bignum_bg (scratch_bignum); +#else + abort (); +#endif /* HAVE_BIGNUM */ + case RATIO_T: +#ifdef HAVE_RATIO + ratio_set_bigfloat (scratch_ratio, XBIGFLOAT_DATA (number)); + return make_ratio_rt (scratch_ratio); +#else + abort (); +#endif + case FLOAT_T: + return make_float (bigfloat_to_double (XBIGFLOAT_DATA (number))); + case BIGFLOAT_T: + /* FIXME: Do we need to change the precision? */ + return number; + } +#else + abort (); +#endif /* HAVE_BIGFLOAT */ + } + abort (); +} + +/* This function promotes its arguments as necessary to make them both the + same type. It destructively modifies its arguments to do so. Characters + and markers are ALWAYS converted to integers. */ +enum number_type +promote_args (Lisp_Object *arg1, Lisp_Object *arg2) +{ + enum number_type type1, type2; + + if (CHARP (*arg1)) + *arg1 = make_int (XCHAR (*arg1)); + else if (MARKERP (*arg1)) + *arg1 = make_int (marker_position (*arg1)); + if (CHARP (*arg2)) + *arg2 = make_int (XCHAR (*arg2)); + else if (MARKERP (*arg2)) + *arg2 = make_int (marker_position (*arg2)); + + CHECK_NUMBER (*arg1); + CHECK_NUMBER (*arg2); + + type1 = get_number_type (*arg1); + type2 = get_number_type (*arg2); + + if (type1 < type2) + { + *arg1 = internal_coerce_number (*arg1, type2, +#ifdef HAVE_BIGFLOAT + type2 == BIGFLOAT_T + ? XBIGFLOAT_GET_PREC (*arg2) : +#endif + 0UL); + return type2; + } + + if (type2 < type1) + { + *arg2 = internal_coerce_number (*arg2, type1, +#ifdef HAVE_BIGFLOAT + type1 == BIGFLOAT_T + ? XBIGFLOAT_GET_PREC (*arg1) : +#endif + 0UL); + return type1; + } + + /* No conversion necessary */ + return type1; +} + +DEFUN ("coerce-number", Fcoerce_number, 2, 3, 0, /* +Convert NUMBER to the indicated type, possibly losing information. +Do not call this function. Use `coerce' instead. + +TYPE is one of the symbols 'fixnum, 'integer, 'ratio, 'float, or 'bigfloat. +Not all of these types may be supported. + +PRECISION is the number of bits of precision to use when converting to +bigfloat; it is ignored otherwise. If nil, the default precision is used. + +Note that some conversions lose information. No error is signaled in such +cases; the information is silently lost. +*/ + (number, type, precision)) +{ + CHECK_SYMBOL (type); + if (EQ (type, Qfixnum)) + return internal_coerce_number (number, FIXNUM_T, 0UL); + else if (EQ (type, Qinteger)) + { + /* If bignums are available, we always convert to one first, then + downgrade to a fixnum if possible. */ +#ifdef HAVE_BIGNUM + return Fcanonicalize_number + (internal_coerce_number (number, BIGNUM_T, 0UL)); +#else + return internal_coerce_number (number, FIXNUM_T, 0UL); +#endif + } +#ifdef HAVE_RATIO + else if (EQ (type, Qratio)) + return internal_coerce_number (number, RATIO_T, 0UL); +#endif + else if (EQ (type, Qfloat)) + return internal_coerce_number (number, FLOAT_T, 0UL); +#ifdef HAVE_BIGFLOAT + else if (EQ (type, Qbigfloat)) + { + unsigned long prec; + + if (NILP (precision)) + prec = bigfloat_get_default_prec (); + else + { + CHECK_INTEGER (precision); +#ifdef HAVE_BIGNUM + if (INTP (precision)) +#endif /* HAVE_BIGNUM */ + prec = (unsigned long) XREALINT (precision); +#ifdef HAVE_BIGNUM + else + { + if (!bignum_fits_ulong_p (XBIGNUM_DATA (precision))) + args_out_of_range (precision, Vbigfloat_max_prec); + prec = bignum_to_ulong (XBIGNUM_DATA (precision)); + } +#endif /* HAVE_BIGNUM */ + } + return internal_coerce_number (number, BIGFLOAT_T, prec); + } +#endif /* HAVE_BIGFLOAT */ + + Fsignal (Qunsupported_type, type); + /* NOTREACHED */ + return Qnil; +} + + +void +syms_of_number (void) +{ +#ifdef HAVE_BIGNUM + INIT_LRECORD_IMPLEMENTATION (bignum); +#endif +#ifdef HAVE_RATIO + INIT_LRECORD_IMPLEMENTATION (ratio); +#endif +#ifdef HAVE_BIGFLOAT + INIT_LRECORD_IMPLEMENTATION (bigfloat); +#endif + + /* Type predicates */ + DEFSYMBOL (Qintegerp); + DEFSYMBOL (Qrationalp); + DEFSYMBOL (Qfloatingp); + DEFSYMBOL (Qrealp); + DEFSYMBOL (Qnumberp); +#ifndef HAVE_BIGNUM + DEFSYMBOL (Qbignump); +#endif +#ifndef HAVE_RATIO + DEFSYMBOL (Qratiop); +#endif +#ifndef HAVE_BIGFLOAT + DEFSYMBOL (Qbigfloatp); +#endif + + /* Functions */ + DEFSUBR (Fbignump); + DEFSUBR (Fintegerp); + DEFSUBR (Fevenp); + DEFSUBR (Foddp); + DEFSUBR (Fratiop); + DEFSUBR (Frationalp); + DEFSUBR (Fnumerator); + DEFSUBR (Fdenominator); + DEFSUBR (Fbigfloatp); + DEFSUBR (Frealp); + DEFSUBR (Fcanonicalize_number); + DEFSUBR (Fcoerce_number); + + /* Errors */ + DEFERROR_STANDARD (Qunsupported_type, Qwrong_type_argument); +} + +void +vars_of_number (void) +{ + /* This variable is a Lisp variable rather than a number variable so that we + can put bignums in it. */ + DEFVAR_LISP_MAGIC ("default-float-precision", &Vdefault_float_precision, /* +The default floating-point precision for newly created floating point values. +This should be 0 for the precision of the machine-supported floating point +type (the C double type), or an unsigned integer no greater than +bigfloat-max-prec (currently the size of a C unsigned long). +*/ default_float_precision_changed); + Vdefault_float_precision = make_int (0); + + DEFVAR_CONST_LISP ("bigfloat-max-prec", &Vbigfloat_max_prec /* +The maximum number of bits of precision a bigfloat can have. +This is currently the value of ULONG_MAX on the target machine. +*/); + + DEFVAR_CONST_INT ("most-negative-fixnum", &Vmost_negative_fixnum /* +The fixnum closest in value to negative infinity. +*/); + Vmost_negative_fixnum = EMACS_INT_MIN; + + DEFVAR_CONST_INT ("most-positive-fixnum", &Vmost_positive_fixnum /* +The fixnum closest in value to positive infinity. +*/); + Vmost_positive_fixnum = EMACS_INT_MAX; + + Fprovide (intern ("number-types")); +#ifdef HAVE_BIGNUM + Fprovide (intern ("bignum")); +#endif +#ifdef HAVE_RATIO + Fprovide (intern ("ratio")); +#endif +#ifdef HAVE_BIGFLOAT + Fprovide (intern ("bigfloat")); +#endif +} + +void +init_number (void) +{ + if (!number_initialized) + { + number_initialized = 1; + +#ifdef WITH_GMP + init_number_gmp (); +#endif +#ifdef WITH_MP + init_number_mp (); +#endif + +#if defined(BIGNUM) && defined(BIGFLOAT) + Vbigfloat_max_prec = make_bignum (0L); + bignum_set_ulong (XBIGNUM_DATA (Vbigfloat_max_prec), ULONG_MAX); +#endif + +#ifdef HAVE_BIGNUM + bignum_init (scratch_bignum); + bignum_init (scratch_bignum2); +#endif + +#ifdef HAVE_RATIO + ratio_init (scratch_ratio); +#endif + +#ifdef HAVE_BIGFLOAT + bigfloat_init (scratch_bigfloat); + bigfloat_init (scratch_bigfloat2); +#endif + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/number.h Mon Apr 05 22:50:11 2004 +0000 @@ -0,0 +1,329 @@ +/* Definitions of numeric types for XEmacs. + Copyright (C) 2004 Jerry James. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +#ifndef INCLUDED_number_h_ +#define INCLUDED_number_h_ + +/* The following types are always defined in the same manner: + fixnum = whatever fits in the Lisp_Object type + integer = union (fixnum, bignum) + rational = union (integer, ratio) + float = C double + floating = union(float, bigfloat) Anybody got a better name? + real = union (rational, floating) + number = real (should be union(real, complex) but no complex yet) + + It is up to the library-specific code to define the remaining types, + namely: bignum, ratio, and bigfloat. Not all of these types may be + available. The top-level configure script should define the symbols + HAVE_BIGNUM, HAVE_RATIO, and HAVE_BIGFLOAT to indicate which it provides. + If some type is not defined by the library, this is what happens: + + - bignum: bignump(x) is false for all x; any attempt to create a bignum + causes an error to be raised. + + - ratio: we define our own structure consisting of two Lisp_Objects, which + are presumed to be integers (i.e., either fixnums or bignums). We do our + own GCD calculation, which is bound to be slow, to keep the ratios + reduced to canonical form. (FIXME: Not yet implemented.) + + - bigfloat: bigfloat(x) is false for all x; any attempt to create a + bigfloat causes an error to be raised. + + We (provide) the following symbols, so that Lisp code has some hope of + using this correctly: + + - (provide 'bignum) if HAVE_BIGNUM + - (provde 'ratio) if HAVE_RATIO + - (provide 'bigfloat) if HAVE_BIGFLOAT +*/ + +/* Load the library definitions */ +#ifdef WITH_GMP +#include "number-gmp.h" +#endif +#ifdef WITH_MP +#include "number-mp.h" +#endif + + +/********************************* Bignums **********************************/ +#ifdef HAVE_BIGNUM + +struct Lisp_Bignum +{ + struct lrecord_header lheader; + bignum data; +}; +typedef struct Lisp_Bignum Lisp_Bignum; + +DECLARE_LRECORD (bignum, Lisp_Bignum); +#define XBIGNUM(x) XRECORD (x, bignum, Lisp_Bignum) +#define wrap_bignum(p) wrap_record (p, bignum) +#define BIGNUMP(x) RECORDP (x, bignum) +#define CHECK_BIGNUM(x) CHECK_RECORD (x, bignum) +#define CONCHECK_BIGNUM(x) CONCHECK_RECORD (x, bignum) + +#define bignum_data(b) (b)->data +#define XBIGNUM_DATA(x) bignum_data (XBIGNUM (x)) + +#define BIGNUM_ARITH_RETURN(b,op) do \ +{ \ + Lisp_Object retval = make_bignum (0); \ + bignum_##op (XBIGNUM_DATA (retval), XBIGNUM_DATA (b)); \ + return Fcanonicalize_number (retval); \ +} while (0) + +#define BIGNUM_ARITH_RETURN1(b,op,arg) do \ +{ \ + Lisp_Object retval = make_bignum(0); \ + bignum_##op (XBIGNUM_DATA (retval), XBIGNUM_DATA (b), arg); \ + return Fcanonicalize_number (retval); \ +} while (0) + +extern Lisp_Object make_bignum (long); +extern Lisp_Object make_bignum_bg (bignum); +extern bignum scratch_bignum, scratch_bignum2; + +#else /* !HAVE_BIGNUM */ + +extern Lisp_Object Qbignump; +#define BIGNUMP(x) 0 +#define CHECK_BIGNUM(x) dead_wrong_type_argument (Qbignump, x) +#define CONCHECK_BIGNUM(x) dead_wrong_type_argument (Qbignump, x) +typedef void bignum; +#define make_bignum(l) This XEmacs does not support bignums +#define make_bignum_bg(b) This XEmacs does not support bignums + +#endif /* HAVE_BIGNUM */ + +EXFUN (Fbignump, 1); + + +/********************************* Integers *********************************/ +extern Lisp_Object Qintegerp; + +#define INTEGERP(x) (INTP(x) || BIGNUMP(x)) +#define CHECK_INTEGER(x) do { \ + if (!INTEGERP (x)) \ + dead_wrong_type_argument (Qintegerp, x); \ + } while (0) +#define CONCHECK_INTEGER(x) do { \ + if (!INTEGERP (x)) \ + x = wrong_type_argument (Qintegerp, x); \ +} while (0) + +#ifdef HAVE_BIGNUM +#define make_integer(x) \ + (NUMBER_FITS_IN_AN_EMACS_INT (x) ? make_int (x) : make_bignum (x)) +#else +#define make_integer(x) make_int (x) +#endif + +extern Fixnum Vmost_negative_fixnum, Vmost_positive_fixnum; +EXFUN (Fintegerp, 1); +EXFUN (Fevenp, 1); +EXFUN (Foddp, 1); + + +/********************************** Ratios **********************************/ +#ifdef HAVE_RATIO + +struct Lisp_Ratio +{ + struct lrecord_header lheader; + ratio data; +}; +typedef struct Lisp_Ratio Lisp_Ratio; + +DECLARE_LRECORD (ratio, Lisp_Ratio); +#define XRATIO(x) XRECORD (x, ratio, Lisp_Ratio) +#define wrap_ratio(p) wrap_record (p, ratio) +#define RATIOP(x) RECORDP (x, ratio) +#define CHECK_RATIO(x) CHECK_RECORD (x, ratio) +#define CONCHECK_RATIO(x) CONCHECK_RECORD (x, ratio) + +#define ratio_data(r) (r)->data + +#define XRATIO_DATA(r) ratio_data (XRATIO (r)) +#define XRATIO_NUMERATOR(r) ratio_numerator (XRATIO_DATA (r)) +#define XRATIO_DENOMINATOR(r) ratio_denominator (XRATIO_DATA (r)) + +#define RATIO_ARITH_RETURN(r,op) do \ +{ \ + Lisp_Object retval = make_ratio (0L, 1UL); \ + ratio_##op (XRATIO_DATA (retval), XRATIO_DATA (r)); \ + return Fcanonicalize_number (retval); \ +} while (0) + +#define RATIO_ARITH_RETURN1(r,op,arg) do \ +{ \ + Lisp_Object retval = make_ratio (0L, 1UL); \ + ratio_##op (XRATIO_DATA (retval), XRATIO_DATA (r), arg); \ + return Fcanonicalize_number (retval); \ +} while (0) + +extern Lisp_Object make_ratio (long, unsigned long); +extern Lisp_Object make_ratio_bg (bignum, bignum); +extern Lisp_Object make_ratio_rt (ratio); +extern ratio scratch_ratio; + +#else /* !HAVE_RATIO */ + +extern Lisp_Object Qratiop; +#define RATIOP(x) 0 +#define CHECK_RATIO(x) dead_wrong_type_argument (Qratiop, x) +#define CONCHECK_RATIO(x) dead_wrong_type_argument (Qratiop, x) +typedef void ratio; +#define make_ratio(n,d) This XEmacs does not support ratios +#define make_ratio_bg(n,d) This XEmacs does not support ratios + +#endif /* HAVE_RATIO */ + +EXFUN (Fratiop, 1); + + +/******************************** Rationals *********************************/ +extern Lisp_Object Qrationalp; + +#define RATIONALP(x) (INTEGERP(x) || RATIOP(x)) +#define CHECK_RATIONAL(x) do { \ + if (!RATIONALP (x)) \ + dead_wrong_type_argument (Qrationalp, x); \ + } while (0) +#define CONCHECK_RATIONAL(x) do { \ + if (!RATIONALP (x)) \ + x = wrong_type_argument (Qrationalp, x); \ +} while (0) + +EXFUN (Frationalp, 1); +EXFUN (Fnumerator, 1); +EXFUN (Fdenominator, 1); + + +/******************************** Bigfloats *********************************/ +#ifdef HAVE_BIGFLOAT +struct Lisp_Bigfloat +{ + struct lrecord_header lheader; + bigfloat bf; +}; +typedef struct Lisp_Bigfloat Lisp_Bigfloat; + +DECLARE_LRECORD (bigfloat, Lisp_Bigfloat); +#define XBIGFLOAT(x) XRECORD (x, bigfloat, Lisp_Bigfloat) +#define wrap_bigfloat(p) wrap_record (p, bigfloat) +#define BIGFLOATP(x) RECORDP (x, bigfloat) +#define CHECK_BIGFLOAT(x) CHECK_RECORD (x, bigfloat) +#define CONCHECK_BIGFLOAT(x) CONCHECK_RECORD (x, bigfloat) + +#define bigfloat_data(f) ((f)->bf) +#define XBIGFLOAT_DATA(x) bigfloat_data (XBIGFLOAT (x)) +#define XBIGFLOAT_GET_PREC(x) bigfloat_get_prec (XBIGFLOAT_DATA (x)) +#define XBIGFLOAT_SET_PREC(x,p) bigfloat_set_prec (XBIGFLOAT_DATA (x), p) + +#define BIGFLOAT_ARITH_RETURN(f,op) do \ +{ \ + Lisp_Object retval = make_bigfloat_bf (f); \ + bigfloat_##op (XBIGFLOAT_DATA (retval), XBIGFLOAT_DATA (f)); \ + return retval; \ +} while (0) + +#define BIGFLOAT_ARITH_RETURN1(f,op,arg) do \ +{ \ + Lisp_Object retval = make_bigfloat_bf (f); \ + bigfloat_##op (XBIGFLOAT_DATA (retval), XBIGFLOAT_DATA (f), arg); \ + return retval; \ +} while (0) + +extern Lisp_Object make_bigfloat (double, unsigned long); +extern Lisp_Object make_bigfloat_bf (bigfloat); +extern Lisp_Object Vdefault_float_precision; +extern bigfloat scratch_bigfloat, scratch_bigfloat2; + +#else /* !HAVE_BIGFLOAT */ + +extern Lisp_Object Qbigfloatp; +#define BIGFLOATP(x) 0 +#define CHECK_BIGFLOAT(x) dead_wrong_type_argument (Qbigfloatp, x) +#define CONCHECK_BIGFLOAT(x) dead_wrong_type_argument (Qbigfloatp, x) +typedef void bigfloat; +#define make_bigfloat(f) This XEmacs does not support bigfloats +#define make_bigfloat_bf(f) This XEmacs does not support bigfloast + +#endif /* HAVE_BIGFLOAT */ + +EXFUN (Fbigfloatp, 1); + +/********************************* Floating *********************************/ +extern Lisp_Object Qfloatingp, Qbigfloat; +extern Lisp_Object Qread_default_float_format, Vread_default_float_format; + +#define FLOATINGP(x) (FLOATP (x) || BIGFLOATP (x)) +#define CHECK_FLOATING(x) do { \ + if (!FLOATINGP (x)) \ + dead_wrong_type_argument (Qfloatingp, x); \ + } while (0) +#define CONCHECK_FLOATING(x) do { \ + if (!FLOATINGP (x)) \ + x = wrong_type_argument (Qfloating, x); \ +} while (0) + +EXFUN (Ffloatp, 1); + + +/********************************** Reals ***********************************/ +extern Lisp_Object Qrealp; + +#define REALP(x) (RATIONALP (x) || FLOATINGP (x)) +#define CHECK_REAL(x) do { \ + if (!REALP (x)) \ + dead_wrong_type_argument (Qrealp, x); \ + } while (0) +#define CONCHECK_REAL(x) do { \ + if (!REALP (x)) \ + x = wrong_type_argument (Qrealp, x); \ +} while (0) + +EXFUN (Frealp, 1); + + +/********************************* Numbers **********************************/ +extern Lisp_Object Qnumberp; + +#define NUMBERP(x) REALP (x) +#define CHECK_NUMBER(x) do { \ + if (!NUMBERP (x)) \ + dead_wrong_type_argument (Qnumberp, x); \ +} while (0) +#define CONCHECK_NUMBER(x) do { \ + if (!NUMBERP (x)) \ + x = wrong_type_argument (Qnumberp, x); \ +} while (0) + +EXFUN (Fcanonicalize_number, 1); + +enum number_type {FIXNUM_T, BIGNUM_T, RATIO_T, FLOAT_T, BIGFLOAT_T}; + +extern enum number_type promote_args (Lisp_Object *, Lisp_Object *); + +#endif /* INCLUDED_number_h_ */
--- a/src/symsinit.h Mon Apr 05 21:50:47 2004 +0000 +++ b/src/symsinit.h Mon Apr 05 22:50:11 2004 +0000 @@ -151,6 +151,7 @@ void syms_of_mule_coding (void); void syms_of_mule_wnn (void); void syms_of_nt (void); +void syms_of_number (void); void syms_of_objects (void); void syms_of_objects_mswindows (void); void syms_of_objects_tty (void); @@ -391,6 +392,7 @@ void vars_of_mule_wnn (void); void reinit_vars_of_mule_wnn (void); void vars_of_nt (void); +void vars_of_number (void); void vars_of_objects (void); void reinit_vars_of_objects (void); void vars_of_objects_tty (void); @@ -548,4 +550,8 @@ void init_event_gtk_late (void); void console_type_create_select_gtk (void); +/* Enhanced number initialization: must be done only at runtime due to complex + interactions with the supporting libraries. */ +void init_number (void); + #endif /* INCLUDED_symsinit_h_ */
--- a/src/sysdep.c Mon Apr 05 21:50:47 2004 +0000 +++ b/src/sysdep.c Mon Apr 05 22:50:11 2004 +0000 @@ -3635,6 +3635,9 @@ srand ((unsigned int)arg); # endif #endif +#ifdef HAVE_BIGNUM + bignum_random_seed ((unsigned long) arg); +#endif } /*
--- a/tests/ChangeLog Mon Apr 05 21:50:47 2004 +0000 +++ b/tests/ChangeLog Mon Apr 05 22:50:11 2004 +0000 @@ -1,3 +1,7 @@ +2004-04-05 Jerry James <james@xemacs.org> + + * automated/lisp-tests.el: Add bignum and ratio tests. + 2004-03-22 Stephen J. Turnbull <stephen@xemacs.org> * XEmacs 21.5.17 "chayote" is released.
--- a/tests/automated/lisp-tests.el Mon Apr 05 21:50:47 2004 +0000 +++ b/tests/automated/lisp-tests.el Mon Apr 05 22:50:11 2004 +0000 @@ -229,8 +229,27 @@ (Assert (= (+ 1.0 1) 2.0)) (Assert (= (+ 1.0 1 1) 3.0)) (Assert (= (+ 1 1 1.0) 3.0)) -(Assert (eq (1+ most-positive-fixnum) most-negative-fixnum)) -(Assert (eq (+ most-positive-fixnum 1) most-negative-fixnum)) +(if (featurep 'bignum) + (progn + (Assert (bignump (1+ most-positive-fixnum))) + (Assert (eq most-positive-fixnum (1- (1+ most-positive-fixnum)))) + (Assert (bignump (+ most-positive-fixnum 1))) + (Assert (eq most-positive-fixnum (- (+ most-positive-fixnum 1) 1))) + (Assert (= (1+ most-positive-fixnum) (- most-negative-fixnum))) + (Assert (zerop (+ (* 3 most-negative-fixnum) (* 3 most-positive-fixnum) + 3)))) + (Assert (eq (1+ most-positive-fixnum) most-negative-fixnum)) + (Assert (eq (+ most-positive-fixnum 1) most-negative-fixnum))) + +(when (featurep 'ratio) + (let ((threefourths (read "3/4")) + (threehalfs (read "3/2")) + (bigpos (div (+ most-positive-fixnum 2) (1+ most-positive-fixnum))) + (bigneg (div (+ most-positive-fixnum 2) most-negative-fixnum)) + (negone (div (1+ most-positive-fixnum) most-negative-fixnum))) + (Assert (= negone -1)) + (Assert (= threehalfs (+ threefourths threefourths))) + (Assert (zerop (+ bigpos bigneg))))) ;; Test `-' (Check-Error wrong-number-of-arguments (-)) @@ -257,8 +276,28 @@ (Assert (= (- 1.5 1) .5)) (Assert (= (- 1 1.5) (- .5))) -(Assert (eq (1- most-negative-fixnum) most-positive-fixnum)) -(Assert (eq (- most-negative-fixnum 1) most-positive-fixnum)) +(if (featurep 'bignum) + (progn + (Assert (bignump (1- most-negative-fixnum))) + (Assert (eq most-negative-fixnum (1+ (1- most-negative-fixnum)))) + (Assert (bignump (- most-negative-fixnum 1))) + (Assert (eq most-negative-fixnum (+ (- most-negative-fixnum 1) 1))) + (Assert (= (1- most-negative-fixnum) (- 0 most-positive-fixnum 2))) + (Assert (eq (- (- most-positive-fixnum most-negative-fixnum) + (* 2 most-positive-fixnum)) + 1))) + (Assert (eq (1- most-negative-fixnum) most-positive-fixnum)) + (Assert (eq (- most-negative-fixnum 1) most-positive-fixnum))) + +(when (featurep 'ratio) + (let ((threefourths (read "3/4")) + (threehalfs (read "3/2")) + (bigpos (div (+ most-positive-fixnum 2) (1+ most-positive-fixnum))) + (bigneg (div most-positive-fixnum most-negative-fixnum)) + (negone (div (1+ most-positive-fixnum) most-negative-fixnum))) + (Assert (= (- negone) 1)) + (Assert (= threefourths (- threehalfs threefourths))) + (Assert (= (- bigpos bigneg) 2)))) ;; Test `/' @@ -286,6 +325,28 @@ (dolist (two '(2 2.0 ?\02)) (Assert (= (/ 3.0 two) 1.5))) +(when (featurep 'bignum) + (let* ((million 1000000) + (billion (* million 1000)) ;; American, not British, billion + (trillion (* billion 1000))) + (Assert (= (/ billion 1000) (/ trillion million) million 1000000.0)) + (Assert (= (/ billion -1000) (/ trillion (- million)) (- million))) + (Assert (= (/ trillion 1000) billion 1000000000.0)) + (Assert (= (/ trillion -1000) (- billion) -1000000000.0)) + (Assert (= (/ trillion 10) (* 100 billion) 100000000000.0)) + (Assert (= (/ (- trillion) 10) (* -100 billion) -100000000000.0)))) + +(when (featurep 'ratio) + (let ((half (div 1 2)) + (fivefourths (div 5 4)) + (fivehalfs (div 5 2))) + (Assert (= half (read "3000000000/6000000000"))) + (Assert (= (/ fivehalfs fivefourths) 2)) + (Assert (= (/ fivefourths fivehalfs) half)) + (Assert (= (- half) (read "-3000000000/6000000000"))) + (Assert (= (/ fivehalfs (- fivefourths)) -2)) + (Assert (= (/ (- fivefourths) fivehalfs) (- half))))) + ;; Test `*' (Assert (= 1 (*))) @@ -306,6 +367,19 @@ (dolist (five '(5 5.0 ?\05)) (Assert (= 30 (* five two three)))))) +(when (featurep 'bignum) + (let ((64K 65536)) + (Assert (= (* 64K 64K) (read "4294967296"))) + (Assert (= (* (- 64K) 64K) (read "-4294967296"))) + (Assert (/= (* -1 most-negative-fixnum) most-negative-fixnum)))) + +(when (featurep 'ratio) + (let ((half (div 1 2)) + (fivefourths (div 5 4)) + (twofifths (div 2 5))) + (Assert (= (* fivefourths twofifths) half)) + (Assert (= (* half twofifths) (read "3/15"))))) + ;; Test `+' (Assert (= 0 (+))) @@ -337,6 +411,20 @@ (Assert (= two (max one two two))) (Assert (= two (max two two one))))) +(when (featurep 'bignum) + (let ((big (1+ most-positive-fixnum)) + (small (1- most-negative-fixnum))) + (Assert (= big (max 1 1000000.0 most-positive-fixnum big))) + (Assert (= small (min -1 -1000000.0 most-negative-fixnum small))))) + +(when (featurep 'ratio) + (let* ((big (1+ most-positive-fixnum)) + (small (1- most-negative-fixnum)) + (bigr (div (* 5 (1+ most-positive-fixnum)) 4)) + (smallr (- bigr))) + (Assert (= bigr (max 1 1000000.0 most-positive-fixnum big bigr))) + (Assert (= smallr (min -1 -1000000.0 most-negative-fixnum small smallr))))) + ;; The byte compiler has special handling for these constructs: (let ((three 3) (five 5)) (Assert (= (+ three five 1) 9)) @@ -476,7 +564,13 @@ (division-test ?\07) (division-test (Int-to-Marker 7))) - +(when (featurep 'bignum) + (let ((big (+ (* 7 most-positive-fixnum 6))) + (negbig (- (* 7 most-negative-fixnum 6)))) + (= (% big (1+ most-positive-fixnum)) most-positive-fixnum) + (= (% negbig (1- most-negative-fixnum)) most-negative-fixnum) + (= (mod big (1+ most-positive-fixnum)) most-positive-fixnum) + (= (mod negbig (1- most-negative-fixnum)) most-negative-fixnum))) ;;----------------------------------------------------- ;; Arithmetic comparison operations @@ -567,6 +661,42 @@ (Assert (= 1 (Int-to-Marker 1))) (Assert (= (point) (point-marker))) +(when (featurep 'bignum) + (let ((big1 (1+ most-positive-fixnum)) + (big2 (* 10 most-positive-fixnum)) + (small1 (1- most-negative-fixnum)) + (small2 (* 10 most-negative-fixnum))) + (Assert (< small2 small1 most-negative-fixnum most-positive-fixnum big1 + big2)) + (Assert (<= small2 small1 most-negative-fixnum most-positive-fixnum big1 + big2)) + (Assert (> big2 big1 most-positive-fixnum most-negative-fixnum small1 + small2)) + (Assert (>= big2 big1 most-positive-fixnum most-negative-fixnum small1 + small2)) + (Assert (/= small2 small1 most-negative-fixnum most-positive-fixnum big1 + big2)))) + +(when (featurep 'ratio) + (let ((big1 (div (* 10 most-positive-fixnum) 4)) + (big2 (div (* 5 most-positive-fixnum) 2)) + (big3 (div (* 7 most-positive-fixnum) 2)) + (small1 (div (* 10 most-negative-fixnum) 4)) + (small2 (div (* 5 most-negative-fixnum) 2)) + (small3 (div (* 7 most-negative-fixnum) 2))) + (Assert (= big1 big2)) + (Assert (= small1 small2)) + (Assert (< small3 small1 most-negative-fixnum most-positive-fixnum big1 + big3)) + (Assert (<= small3 small2 small1 most-negative-fixnum most-positive-fixnum + big1 big2 big3)) + (Assert (> big3 big1 most-positive-fixnum most-negative-fixnum small1 + small3)) + (Assert (>= big3 big2 big1 most-positive-fixnum most-negative-fixnum + small1 small2 small3)) + (Assert (/= big3 big1 most-positive-fixnum most-negative-fixnum small1 + small3)))) + ;;----------------------------------------------------- ;; testing list-walker functions ;;----------------------------------------------------- @@ -1135,10 +1265,16 @@ ;;; "%u" is undocumented, and Emacs Lisp has no unsigned type. ;;; What to do if "%u" is used with a negative number? -;;; The most reasonable thing seems to be to print an un-read-able number. -;;; The printed value might be useful to a human, if not to Emacs Lisp. -(Check-Error invalid-read-syntax (read (format "%u" most-negative-fixnum))) -(Check-Error invalid-read-syntax (read (format "%u" -1))) +;;; For non-bignum XEmacsen, the most reasonable thing seems to be to print an +;;; un-read-able number. The printed value might be useful to a human, if not +;;; to Emacs Lisp. +;;; For bignum XEmacsen, we make %u with a negative value throw an error. +(if (featurep 'bignum) + (progn + (Check-Error wrong-type-argument (format "%u" most-negative-fixnum)) + (Check-Error wrong-type-argument (format "%u" -1))) + (Check-Error invalid-read-syntax (read (format "%u" most-negative-fixnum))) + (Check-Error invalid-read-syntax (read (format "%u" -1)))) ;; Check all-completions ignore element start with space. (Assert (not (all-completions "" '((" hidden" . "object")))))