From: Paul Eggert Date: Tue, 5 Nov 2019 07:10:12 +0000 (-0800) Subject: Don’t signal overflow for (expt 1 bignum) X-Git-Tag: emacs-27.0.90~741 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=5ab29400a4e9b29928aaf63d1f89a0b059491b29;p=emacs.git Don’t signal overflow for (expt 1 bignum) Similarly for (expt 0 bignum) and (expt -1 bignum). The result is always a -1, 0 or 1, so do not signal overflow. * src/data.c (expt_integer): Do not signal an overflow if -1 <= X <= 1. Be clearer about when overflow is signaled. * test/src/floatfns-tests.el (bignum-expt): Test this. --- diff --git a/src/data.c b/src/data.c index 1d9222e75a7..a338dadfb69 100644 --- a/src/data.c +++ b/src/data.c @@ -3290,14 +3290,29 @@ In this case, the sign bit is duplicated. */) Lisp_Object expt_integer (Lisp_Object x, Lisp_Object y) { + /* Special cases for -1 <= x <= 1, which never overflow. */ + if (EQ (x, make_fixnum (1))) + return x; + if (EQ (x, make_fixnum (0))) + return EQ (x, y) ? make_fixnum (1) : x; + if (EQ (x, make_fixnum (-1))) + return ((FIXNUMP (y) ? XFIXNUM (y) & 1 : mpz_odd_p (*xbignum_val (y))) + ? x : make_fixnum (1)); + unsigned long exp; - if (TYPE_RANGED_FIXNUMP (unsigned long, y)) - exp = XFIXNUM (y); - else if (MOST_POSITIVE_FIXNUM < ULONG_MAX && BIGNUMP (y) - && mpz_fits_ulong_p (*xbignum_val (y))) - exp = mpz_get_ui (*xbignum_val (y)); + if (FIXNUMP (y)) + { + if (ULONG_MAX < XFIXNUM (y)) + overflow_error (); + exp = XFIXNUM (y); + } else - overflow_error (); + { + if (ULONG_MAX <= MOST_POSITIVE_FIXNUM + || !mpz_fits_ulong_p (*xbignum_val (y))) + overflow_error (); + exp = mpz_get_ui (*xbignum_val (y)); + } emacs_mpz_pow_ui (mpz[0], *bignum_integer (&mpz[0], x), exp); return make_integer_mpz (); diff --git a/test/src/floatfns-tests.el b/test/src/floatfns-tests.el index 643866f1146..62201a877d0 100644 --- a/test/src/floatfns-tests.el +++ b/test/src/floatfns-tests.el @@ -51,7 +51,12 @@ (ert-deftest bignum-expt () (dolist (n (list most-positive-fixnum (1+ most-positive-fixnum) most-negative-fixnum (1- most-negative-fixnum) + (* 5 most-negative-fixnum) + (* 5 (1+ most-positive-fixnum)) -2 -1 0 1 2)) + (should (or (<= n 0) (= (expt 0 n) 0))) + (should (= (expt 1 n) 1)) + (should (or (< n 0) (= (expt -1 n) (if (zerop (logand n 1)) 1 -1)))) (should (= (expt n 0) 1)) (should (= (expt n 1) n)) (should (= (expt n 2) (* n n)))