]> git.eshelyaron.com Git - emacs.git/commitdiff
Support (ash INTEGER BIGNUM)
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 18 Dec 2018 20:21:27 +0000 (12:21 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 18 Dec 2018 20:23:02 +0000 (12:23 -0800)
* src/data.c (emacs_mpz_mul_2exp): 2nd arg is now a
nonnegative EMACS_INT not mp_bitcnt_t, to simplify checking.
(Fash): Support COUNT values that are bignums or that
exceed mp_bitcnt_t range.
* test/src/data-tests.el (data-tests-ash-lsh): Test this.

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

index 0980cf99886b99587d6a0e2cfd9c5612636fe786..c64adb6635e39398e2342f8ff13a35dbe446f2af 100644 (file)
@@ -2414,14 +2414,14 @@ emacs_mpz_mul (mpz_t rop, mpz_t const op1, mpz_t const op2)
 }
 
 static void
-emacs_mpz_mul_2exp (mpz_t rop, mpz_t const op1, mp_bitcnt_t op2)
+emacs_mpz_mul_2exp (mpz_t rop, mpz_t const op1, EMACS_INT op2)
 {
   /* Fudge factor derived from GMP 6.1.2, to avoid an abort in
      mpz_mul_2exp (look for the '+ 1' in its source code).  */
   enum { mul_2exp_extra_limbs = 1 };
   enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - mul_2exp_extra_limbs) };
 
-  mp_bitcnt_t op2limbs = op2 / GMP_NUMB_BITS;
+  EMACS_INT op2limbs = op2 / GMP_NUMB_BITS;
   if (lim - emacs_mpz_size (op1) < op2limbs)
     overflow_error ();
   mpz_mul_2exp (rop, op1, op2);
@@ -3251,12 +3251,21 @@ If COUNT is negative, shifting is actually to the right.
 In this case, the sign bit is duplicated.  */)
   (Lisp_Object value, Lisp_Object count)
 {
-  /* The negative of the minimum value of COUNT that fits into a fixnum,
-     such that mpz_fdiv_q_exp supports -COUNT.  */
-  EMACS_INT minus_count_min = min (-MOST_NEGATIVE_FIXNUM,
-                                  TYPE_MAXIMUM (mp_bitcnt_t));
   CHECK_INTEGER (value);
-  CHECK_RANGED_INTEGER (count, - minus_count_min, TYPE_MAXIMUM (mp_bitcnt_t));
+  CHECK_INTEGER (count);
+
+  if (! FIXNUMP (count))
+    {
+      if (EQ (value, make_fixnum (0)))
+       return value;
+      if (mpz_sgn (XBIGNUM (count)->value) < 0)
+       {
+         EMACS_INT v = (FIXNUMP (value) ? XFIXNUM (value)
+                        : mpz_sgn (XBIGNUM (value)->value));
+         return make_fixnum (v < 0 ? -1 : 0);
+       }
+      overflow_error ();
+    }
 
   if (XFIXNUM (count) <= 0)
     {
@@ -3275,7 +3284,11 @@ In this case, the sign bit is duplicated.  */)
 
   mpz_t *zval = bignum_integer (&mpz[0], value);
   if (XFIXNUM (count) < 0)
-    mpz_fdiv_q_2exp (mpz[0], *zval, - XFIXNUM (count));
+    {
+      if (TYPE_MAXIMUM (mp_bitcnt_t) < - XFIXNUM (count))
+       return make_fixnum (mpz_sgn (*zval) < 0 ? -1 : 0);
+      mpz_fdiv_q_2exp (mpz[0], *zval, - XFIXNUM (count));
+    }
   else
     emacs_mpz_mul_2exp (mpz[0], *zval, XFIXNUM (count));
   return make_integer_mpz ();
index d41c762328988ecf6b750d33b7e57c0a81650fb7..bbf7e2a2394aa237a78766e47094f84196b4af77 100644 (file)
@@ -656,6 +656,10 @@ comparing the subr with a much slower lisp implementation."
 (ert-deftest data-tests-ash-lsh ()
   (should (= (ash most-negative-fixnum 1)
              (* most-negative-fixnum 2)))
+  (should (= (ash 0 (* 2 most-positive-fixnum)) 0))
+  (should (= (ash 1000 (* 2 most-negative-fixnum)) 0))
+  (should (= (ash -1000 (* 2 most-negative-fixnum)) -1))
+  (should (= (ash (* 2 most-negative-fixnum) (* 2 most-negative-fixnum)) -1))
   (should (= (lsh most-negative-fixnum 1)
              (* most-negative-fixnum 2)))
   (should (= (ash (* 2 most-negative-fixnum) -1)