Mercurial > hg > xemacs-beta
diff src/data.c @ 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 | ac1be85b4a5f |
children | 4529ff71e646 |
line wrap: on
line diff
--- 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);