# HG changeset patch # User Jerry James # Date 1255371004 21600 # Node ID fcc7e89d5e68391a738b865eddc65238d4a475f9 # Parent dca5bb2adff1b80bbab692ed963d06a22e9be546 Properly handle continuable divide-by-zero errors. Fix truncation of a zero-valued ratio. See xemacs-patches message <870180fe0910080956h5d674f03q185d11aa6fc57bd2@mail.gmail.com>. diff -r dca5bb2adff1 -r fcc7e89d5e68 src/ChangeLog --- a/src/ChangeLog Mon Oct 12 17:19:52 2009 +0100 +++ b/src/ChangeLog Mon Oct 12 12:10:04 2009 -0600 @@ -1,3 +1,30 @@ +2009-10-08 Jerry James + + * bytecode.c (bytecode_arithop): Make divide-by-zero errors + noncontinuable. + * floatfns.c (arith_error2): New macro for signaling divide-by-zero. + (ceiling_two_fixnum): Handle a value returned from a continuable error. + (ceiling_two_bignum): Ditto. + (ceiling_two_ratio): Ditto. + (ceiling_two_bigfloat): Ditto. + (ceiling_two_float): Ditto. + (floor_two_fixnum): Ditto. + (floor_two_bignum): Ditto. + (floor_two_ratio): Ditto. + (floor_two_bigfloat): Ditto. + (floor_two_float): Ditto. + (round_two_fixnum): Ditto. + (round_two_bignum): Ditto. + (round_two_ratio): Ditto. + (round_two_bigfloat): Ditto. + (round_two_float): Ditto. + (truncate_two_fixnum): Ditto. + (truncate_two_bignum): Ditto. + (truncate_two_ratio): Ditto. + (truncate_two_bigfloat): Ditto. + (truncate_two_float): Ditto. + (truncate_one_ratio): Truncating zero should result in zero. + 2009-10-10 Aidan Kehoe * rangetab.c (Frange_table_type): diff -r dca5bb2adff1 -r fcc7e89d5e68 src/bytecode.c --- a/src/bytecode.c Mon Oct 12 17:19:52 2009 +0100 +++ b/src/bytecode.c Mon Oct 12 12:10:04 2009 -0600 @@ -432,7 +432,8 @@ ival1 *= ival2; break; #endif case Bquo: - if (ival2 == 0) Fsignal (Qarith_error, Qnil); + if (ival2 == 0) + signal_error_2 (Qarith_error, "division by zero", obj1, obj2); ival1 /= ival2; break; case Bmax: if (ival1 < ival2) ival1 = ival2; break; @@ -458,7 +459,7 @@ break; case Bquo: if (bignum_sign (XBIGNUM_DATA (obj2)) == 0) - Fsignal (Qarith_error, Qnil); + signal_error_2 (Qarith_error, "division by zero", obj1, obj2); bignum_div (scratch_bignum, XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2)); break; @@ -486,7 +487,7 @@ break; case Bquo: if (ratio_sign (XRATIO_DATA (obj2)) == 0) - Fsignal (Qarith_error, Qnil); + signal_error_2 (Qarith_error, "division by zero", obj1, obj2); ratio_div (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2)); break; case Bmax: @@ -518,7 +519,7 @@ break; case Bquo: if (bigfloat_sign (XBIGFLOAT_DATA (obj2)) == 0) - Fsignal (Qarith_error, Qnil); + signal_error_2 (Qarith_error, "division by zero", obj1, obj2); bigfloat_div (scratch_bigfloat, XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2)); break; @@ -540,7 +541,8 @@ case Bdiff: dval1 -= dval2; break; case Bmult: dval1 *= dval2; break; case Bquo: - if (dval2 == 0.0) Fsignal (Qarith_error, Qnil); + if (dval2 == 0.0) + signal_error_2 (Qarith_error, "division by zero", obj1, obj2); dval1 /= dval2; break; case Bmax: if (dval1 < dval2) dval1 = dval2; break; @@ -585,7 +587,8 @@ case Bdiff: ival1 -= ival2; break; case Bmult: ival1 *= ival2; break; case Bquo: - if (ival2 == 0) Fsignal (Qarith_error, Qnil); + if (ival2 == 0) + signal_error_2 (Qarith_error, "division by zero", obj1, obj2); ival1 /= ival2; break; case Bmax: if (ival1 < ival2) ival1 = ival2; break; @@ -603,7 +606,8 @@ case Bdiff: dval1 -= dval2; break; case Bmult: dval1 *= dval2; break; case Bquo: - if (dval2 == 0) Fsignal (Qarith_error, Qnil); + if (dval2 == 0) + signal_error_2 (Qarith_error, "division by zero", obj1, obj2); dval1 /= dval2; break; case Bmax: if (dval1 < dval2) dval1 = dval2; break; diff -r dca5bb2adff1 -r fcc7e89d5e68 src/floatfns.c --- a/src/floatfns.c Mon Oct 12 17:19:52 2009 +0100 +++ b/src/floatfns.c Mon Oct 12 12:10:04 2009 -0600 @@ -108,6 +108,8 @@ #define arith_error(op,arg) \ Fsignal (Qarith_error, list2 (build_msg_string (op), arg)) +#define arith_error2(op,a1,a2) \ + Fsignal (Qarith_error, list3 (build_msg_string (op), a1, a2)) #define range_error(op,arg) \ Fsignal (Qrange_error, list2 (build_msg_string (op), arg)) #define range_error2(op,a1,a2) \ @@ -889,7 +891,6 @@ BIGFLOAT, return_float); \ return conversion##_one_mundane_arg (number, divisor, \ return_float) - #define CONVERT_WITHOUT_NUMBER_TYPES(conversion, return_float) \ if (!NILP (divisor)) \ @@ -943,23 +944,23 @@ #define MAYBE_ONE_ARG_BIGNUM(converse, return_float) \ if (BIGNUM_P (number)) \ - return conversion##_one_bignum (number, divisor, return_float) + return conversion##_one_bignum (number, divisor, return_float) #else #define MAYBE_TWO_ARGS_BIGNUM(conversion, return_float) -#define MAYBE_ONE_ARG_BIGNUM(converse, return_float) +#define MAYBE_ONE_ARG_BIGNUM(converse, return_float) #endif -#ifdef HAVE_RATIO +#ifdef HAVE_RATIO #define MAYBE_TWO_ARGS_RATIO(conversion, return_float) \ case RATIO_T: \ return conversion##_two_ratio (number, divisor, return_float) #define MAYBE_ONE_ARG_RATIO(conversion, return_float) \ if (RATIOP (number)) \ - return conversion##_one_ratio (number, divisor, return_float) + return conversion##_one_ratio (number, divisor, return_float) #else #define MAYBE_TWO_ARGS_RATIO(conversion, return_float) -#define MAYBE_ONE_ARG_RATIO(converse, return_float) +#define MAYBE_ONE_ARG_RATIO(converse, return_float) #endif #ifdef HAVE_BIGFLOAT @@ -969,10 +970,10 @@ #define MAYBE_ONE_ARG_BIGFLOAT(conversion, return_float) \ if (BIGFLOATP (number)) \ - return conversion##_one_bigfloat (number, divisor, return_float) + return conversion##_one_bigfloat (number, divisor, return_float) #else #define MAYBE_TWO_ARGS_BIGFLOAT(conversion, return_float) -#define MAYBE_ONE_ARG_BIGFLOAT(converse, return_float) +#define MAYBE_ONE_ARG_BIGFLOAT(converse, return_float) #endif #define MAYBE_TWO_ARGS_WITH_NUMBER_TYPES(convers, upcase, return_float) \ @@ -1015,7 +1016,7 @@ EMACS_INT i3 = 0, i4 = 0; if (i2 == 0) - Fsignal (Qarith_error, Qnil); + return arith_error2 ("ceiling", number, divisor); /* With C89's integer /, the result is implementation-defined if either operand is negative, so use only nonnegative operands. Here we do @@ -1080,9 +1081,7 @@ Lisp_Object res0, res1; if (bignum_sign (XBIGNUM_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("ceiling", number, divisor); bignum_ceil (scratch_bignum, XBIGNUM_DATA (number), XBIGNUM_DATA (divisor)); @@ -1112,9 +1111,7 @@ Lisp_Object res0, res1; if (ratio_sign (XRATIO_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("ceiling", number, divisor); ratio_div (scratch_ratio, XRATIO_DATA (number), XRATIO_DATA (divisor)); @@ -1149,9 +1146,7 @@ Lisp_Object res0; if (bigfloat_sign (XBIGFLOAT_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("ceiling", number, divisor); bigfloat_set_prec (scratch_bigfloat, max (XBIGFLOAT_GET_PREC (number), XBIGFLOAT_GET_PREC (divisor))); @@ -1248,12 +1243,10 @@ double f2 = extract_float (divisor); double f0, remain; Lisp_Object res0; - + if (f2 == 0.0) - { - Fsignal (Qarith_error, Qnil); - } - + return arith_error2 ("ceiling", number, divisor); + IN_FLOAT2 (f0 = ceil (f1 / f2), MAYBE_EFF("ceiling"), number, divisor); IN_FLOAT2 (remain = f1 - (f0 * f2), MAYBE_EFF("ceiling"), number, divisor); @@ -1306,7 +1299,7 @@ #ifdef HAVE_BIGNUM else if (BIGNUMP (number)) { - return values2 (make_float + return values2 (make_float (bignum_to_double (XBIGNUM_DATA (number))), Qzero); } @@ -1323,7 +1316,7 @@ return values2 (number, Qzero); } } - + MAYBE_CHAR_OR_MARKER (ceiling); return Ffceiling (wrong_type_argument (Qnumberp, number), divisor); @@ -1339,9 +1332,7 @@ Lisp_Object res0; if (i2 == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("floor", number, divisor); /* With C89's integer /, the result is implementation-defined if either operand is negative, so use only nonnegative operands. Notice also that @@ -1373,9 +1364,7 @@ Lisp_Object res0, res1; if (bignum_sign (XBIGNUM_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("floor", number, divisor); bignum_floor (scratch_bignum, XBIGNUM_DATA (number), XBIGNUM_DATA (divisor)); @@ -1412,9 +1401,7 @@ Lisp_Object res0, res1; if (ratio_sign (XRATIO_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("floor", number, divisor); ratio_div (scratch_ratio, XRATIO_DATA (number), XRATIO_DATA (divisor)); @@ -1449,9 +1436,7 @@ Lisp_Object res0; if (bigfloat_sign (XBIGFLOAT_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("floor", number, divisor); bigfloat_set_prec (scratch_bigfloat, max (XBIGFLOAT_GET_PREC (number), XBIGFLOAT_GET_PREC (divisor))); @@ -1546,12 +1531,10 @@ double f1 = extract_float (number); double f2 = extract_float (divisor); double f0, remain; - + if (f2 == 0.0) - { - Fsignal (Qarith_error, Qnil); - } - + return arith_error2 ("floor", number, divisor); + IN_FLOAT2 (f0 = floor (f1 / f2), MAYBE_EFF ("floor"), number, divisor); IN_FLOAT2 (remain = f1 - (f0 * f2), MAYBE_EFF ("floor"), number, divisor); @@ -1621,17 +1604,14 @@ /* Algorithm taken from cl-extra.el, now to be found as cl-round in tests/automated/lisp-tests.el. */ static Lisp_Object -round_two_fixnum (Lisp_Object number, Lisp_Object divisor, - int return_float) +round_two_fixnum (Lisp_Object number, Lisp_Object divisor, int return_float) { EMACS_INT i1 = XREALINT (number); EMACS_INT i2 = XREALINT (divisor); EMACS_INT i0, hi2, flooring, floored, flsecond; if (i2 == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("round", number, divisor); hi2 = i2 < 0 ? -( -i2 / 2) : i2 / 2; @@ -1716,15 +1696,12 @@ } static Lisp_Object -round_two_bignum (Lisp_Object number, Lisp_Object divisor, - int return_float) +round_two_bignum (Lisp_Object number, Lisp_Object divisor, int return_float) { Lisp_Object res0, res1; if (bignum_sign (XBIGNUM_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("round", number, divisor); round_two_bignum_1 (XBIGNUM_DATA (number), XBIGNUM_DATA (divisor), &res0, &res1); @@ -1750,12 +1727,10 @@ Lisp_Object res0, res1; if (ratio_sign (XRATIO_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("round", number, divisor); ratio_div (scratch_ratio, XRATIO_DATA (number), XRATIO_DATA (divisor)); - + round_two_bignum_1 (ratio_numerator (scratch_ratio), ratio_denominator (scratch_ratio), &res0, &res1); @@ -1766,7 +1741,7 @@ ratio_set_bignum (scratch_ratio2, XBIGNUM_DATA (res0)); ratio_mul (scratch_ratio, scratch_ratio2, XRATIO_DATA (divisor)); ratio_sub (scratch_ratio, XRATIO_DATA (number), scratch_ratio); - + res1 = Fcanonicalize_number (make_ratio_rt (scratch_ratio)); } @@ -1853,9 +1828,7 @@ XBIGFLOAT_GET_PREC (divisor)); if (bigfloat_sign (XBIGFLOAT_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("round", number, divisor); bigfloat_init (divided); bigfloat_set_prec (divided, prec); @@ -1866,7 +1839,7 @@ bigfloat_set_prec (scratch_bigfloat, prec); bigfloat_set_prec (scratch_bigfloat2, prec); - + bigfloat_mul (scratch_bigfloat, XBIGFLOAT_DATA (res0), XBIGFLOAT_DATA (divisor)); bigfloat_sub (scratch_bigfloat2, XBIGFLOAT_DATA (number), @@ -1921,7 +1894,7 @@ Lisp_Object res0 = round_one_bigfloat_1 (XBIGFLOAT_DATA (number)); Lisp_Object res1; - bigfloat_sub (scratch_bigfloat, XBIGFLOAT_DATA (number), + bigfloat_sub (scratch_bigfloat, XBIGFLOAT_DATA (number), XBIGFLOAT_DATA (res0)); res1 = make_bigfloat_bf (scratch_bigfloat); @@ -1948,12 +1921,12 @@ double f1 = extract_float (number); double f2 = extract_float (divisor); double f0, remain; - + if (f2 == 0.0) - Fsignal (Qarith_error, Qnil); + return arith_error2 ("round", number, divisor); IN_FLOAT2 ((f0 = emacs_rint (f1 / f2)), MAYBE_EFF ("round"), number, - divisor); + divisor); IN_FLOAT2 (remain = f1 - (f0 * f2), MAYBE_EFF ("round"), number, divisor); if (return_float) @@ -1973,7 +1946,7 @@ double d; /* Screw the prevailing rounding mode. */ IN_FLOAT ((d = emacs_rint (XFLOAT_DATA (number))), MAYBE_EFF ("round"), - number); + number); if (return_float) { @@ -1982,7 +1955,7 @@ else { return values2 ((float_to_int (d, MAYBE_EFF ("round"), number, - Qunbound)), + Qunbound)), make_float (XFLOAT_DATA (number) - d)); } } @@ -2014,11 +1987,11 @@ if (return_float) { - return Ffround (wrong_type_argument (Qnumberp, number), divisor); + return Ffround (wrong_type_argument (Qnumberp, number), divisor); } else { - return Fround (wrong_type_argument (Qnumberp, number), divisor); + return Fround (wrong_type_argument (Qnumberp, number), divisor); } } @@ -2031,7 +2004,7 @@ EMACS_INT i0; if (i2 == 0) - Fsignal (Qarith_error, Qnil); + return arith_error2 ("truncate", number, divisor); /* We're truncating towards zero, so apart from avoiding the C89 implementation-defined behaviour with truncation and negative numbers, @@ -2058,9 +2031,7 @@ Lisp_Object res0; if (bignum_sign (XBIGNUM_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("truncate", number, divisor); bignum_div (scratch_bignum, XBIGNUM_DATA (number), XBIGNUM_DATA (divisor)); @@ -2096,9 +2067,7 @@ Lisp_Object res0; if (ratio_sign (XRATIO_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("truncate", number, divisor); ratio_div (scratch_ratio, XRATIO_DATA (number), XRATIO_DATA (divisor)); @@ -2138,9 +2107,7 @@ XBIGFLOAT_GET_PREC (divisor)); if (bigfloat_sign (XBIGFLOAT_DATA (divisor)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("truncate", number, divisor); bigfloat_set_prec (scratch_bigfloat, prec); bigfloat_set_prec (scratch_bigfloat2, prec); @@ -2162,7 +2129,7 @@ res0 = make_int ((EMACS_INT) bigfloat_to_long (scratch_bigfloat)); #endif /* HAVE_BIGNUM */ } - + bigfloat_mul (scratch_bigfloat2, scratch_bigfloat, XBIGFLOAT_DATA (divisor)); bigfloat_sub (scratch_bigfloat, XBIGFLOAT_DATA (number), scratch_bigfloat2); @@ -2178,9 +2145,7 @@ Lisp_Object res0; if (ratio_sign (XRATIO_DATA (number)) == 0) - { - Fsignal (Qarith_error, Qnil); - } + return Qzero; bignum_div (scratch_bignum, XRATIO_NUMERATOR (number), XRATIO_DENOMINATOR (number)); @@ -2234,7 +2199,7 @@ bigfloat_sub (scratch_bigfloat2, XBIGFLOAT_DATA (number), scratch_bigfloat); return - values2 (res0, + values2 (res0, Fcanonicalize_number (make_bigfloat_bf (scratch_bigfloat2))); } #endif /* HAVE_BIGFLOAT */ @@ -2247,11 +2212,9 @@ double f2 = extract_float (divisor); double f0, remain; Lisp_Object res0; - + if (f2 == 0.0) - { - Fsignal (Qarith_error, Qnil); - } + return arith_error2 ("truncate", number, divisor); res0 = float_to_int (f1 / f2, MAYBE_EFF ("truncate"), number, Qunbound); f0 = extract_float (res0); @@ -2325,7 +2288,7 @@ Return the smallest integer no less than NUMBER. (Round toward +inf.) With optional argument DIVISOR, return the smallest integer no less than -the quotient of NUMBER and DIVISOR. +the quotient of NUMBER and DIVISOR. This function returns multiple values; see `multiple-value-bind' and `multiple-value-call'. The second returned value is the remainder in the