Make ash and lsh handle bignums

* src/data.c (ash_lsh_impl): Handle bignums.
* test/src/data-tests.el (data-tests-ash-lsh): New test.
This commit is contained in:
Tom Tromey 2018-07-08 09:22:17 -06:00
parent cca0e79ea8
commit 27980e3604
2 changed files with 34 additions and 9 deletions

View file

@ -3298,18 +3298,37 @@ ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh)
Lisp_Object val;
CHECK_FIXNUM (value);
CHECK_INTEGER (value);
CHECK_FIXNUM (count);
if (XINT (count) >= EMACS_INT_WIDTH)
XSETINT (val, 0);
else if (XINT (count) > 0)
XSETINT (val, XUINT (value) << XINT (count));
else if (XINT (count) <= -EMACS_INT_WIDTH)
XSETINT (val, lsh ? 0 : XINT (value) < 0 ? -1 : 0);
if (BIGNUMP (value))
{
mpz_t result;
mpz_init (result);
if (XINT (count) >= 0)
mpz_mul_2exp (result, XBIGNUM (value)->value, XINT (count));
else
mpz_tdiv_q_2exp (result, XBIGNUM (value)->value, - XINT (count));
val = make_number (result);
mpz_clear (result);
}
else
XSETINT (val, (lsh ? XUINT (value) >> -XINT (count)
: XINT (value) >> -XINT (count)));
{
/* Just do the work as bignums to make the code simpler. */
mpz_t result;
eassume (FIXNUMP (value));
if (lsh)
mpz_init_set_ui (result, XUINT (value));
else
mpz_init_set_si (result, XINT (value));
if (XINT (count) >= 0)
mpz_mul_2exp (result, result, XINT (count));
else
mpz_tdiv_q_2exp (result, result, - XINT (count));
val = make_number (result);
mpz_clear (result);
}
return val;
}

View file

@ -614,4 +614,10 @@ comparing the subr with a much slower lisp implementation."
(data-tests-check-sign (% -1 -3) (% nb1 nb3))
(data-tests-check-sign (mod -1 -3) (mod nb1 nb3))))
(ert-deftest data-tests-ash-lsh ()
(should (= (ash most-negative-fixnum 1)
(* most-negative-fixnum 2)))
(should (= (lsh most-negative-fixnum 1)
(* (abs most-negative-fixnum) 2))))
;;; data-tests.el ends here