summaryrefslogtreecommitdiff
path: root/src/data.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2019-11-04 23:10:12 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2019-11-04 23:39:54 -0800
commit5ab29400a4e9b29928aaf63d1f89a0b059491b29 (patch)
treed48d567ff49bf4f84fe5423de8147a3c89998048 /src/data.c
parent96c8e4fa414f69790fc8b2cc8ded9c758511326f (diff)
downloademacs-5ab29400a4e9b29928aaf63d1f89a0b059491b29.tar.gz
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.
Diffstat (limited to 'src/data.c')
-rw-r--r--src/data.c27
1 files changed, 21 insertions, 6 deletions
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 ();