1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-27 07:37:33 +00:00

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.
This commit is contained in:
Paul Eggert 2019-11-04 23:10:12 -08:00
parent 96c8e4fa41
commit 5ab29400a4
2 changed files with 26 additions and 6 deletions

View 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 ();

View File

@ -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)))