]> git.eshelyaron.com Git - emacs.git/commitdiff
Don’t signal overflow for (expt 1 bignum)
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 5 Nov 2019 07:10:12 +0000 (23:10 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 5 Nov 2019 07:39:54 +0000 (23:39 -0800)
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.

src/data.c
test/src/floatfns-tests.el

index 1d9222e75a7c0e8cabbe2da24983c418808d906c..a338dadfb69e5f365ab7ffbc648b27c656247b5d 100644 (file)
@@ -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 ();
index 643866f114698eb8326e824c567e9f58c42cbdb2..62201a877d07c1163791a3d55dfff730c766c743 100644 (file)
 (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)))