diff options
| author | Paul Eggert | 2018-12-18 12:21:27 -0800 |
|---|---|---|
| committer | Paul Eggert | 2018-12-18 12:23:02 -0800 |
| commit | cdaaaf2e1bd1f8ad2784ffc8265aa642da2d1190 (patch) | |
| tree | 3dbe9cc04690882db9d4fae33a1d69bc32b996a2 | |
| parent | 5a04e8261458d887c7b7d7c259053f236379cf78 (diff) | |
| download | emacs-cdaaaf2e1bd1f8ad2784ffc8265aa642da2d1190.tar.gz emacs-cdaaaf2e1bd1f8ad2784ffc8265aa642da2d1190.zip | |
Support (ash INTEGER BIGNUM)
* 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.
| -rw-r--r-- | src/data.c | 29 | ||||
| -rw-r--r-- | test/src/data-tests.el | 4 |
2 files changed, 25 insertions, 8 deletions
diff --git a/src/data.c b/src/data.c index 0980cf99886..c64adb6635e 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -2414,14 +2414,14 @@ emacs_mpz_mul (mpz_t rop, mpz_t const op1, mpz_t const op2) | |||
| 2414 | } | 2414 | } |
| 2415 | 2415 | ||
| 2416 | static void | 2416 | static void |
| 2417 | emacs_mpz_mul_2exp (mpz_t rop, mpz_t const op1, mp_bitcnt_t op2) | 2417 | emacs_mpz_mul_2exp (mpz_t rop, mpz_t const op1, EMACS_INT op2) |
| 2418 | { | 2418 | { |
| 2419 | /* Fudge factor derived from GMP 6.1.2, to avoid an abort in | 2419 | /* Fudge factor derived from GMP 6.1.2, to avoid an abort in |
| 2420 | mpz_mul_2exp (look for the '+ 1' in its source code). */ | 2420 | mpz_mul_2exp (look for the '+ 1' in its source code). */ |
| 2421 | enum { mul_2exp_extra_limbs = 1 }; | 2421 | enum { mul_2exp_extra_limbs = 1 }; |
| 2422 | enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - mul_2exp_extra_limbs) }; | 2422 | enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - mul_2exp_extra_limbs) }; |
| 2423 | 2423 | ||
| 2424 | mp_bitcnt_t op2limbs = op2 / GMP_NUMB_BITS; | 2424 | EMACS_INT op2limbs = op2 / GMP_NUMB_BITS; |
| 2425 | if (lim - emacs_mpz_size (op1) < op2limbs) | 2425 | if (lim - emacs_mpz_size (op1) < op2limbs) |
| 2426 | overflow_error (); | 2426 | overflow_error (); |
| 2427 | mpz_mul_2exp (rop, op1, op2); | 2427 | mpz_mul_2exp (rop, op1, op2); |
| @@ -3251,12 +3251,21 @@ If COUNT is negative, shifting is actually to the right. | |||
| 3251 | In this case, the sign bit is duplicated. */) | 3251 | In this case, the sign bit is duplicated. */) |
| 3252 | (Lisp_Object value, Lisp_Object count) | 3252 | (Lisp_Object value, Lisp_Object count) |
| 3253 | { | 3253 | { |
| 3254 | /* The negative of the minimum value of COUNT that fits into a fixnum, | ||
| 3255 | such that mpz_fdiv_q_exp supports -COUNT. */ | ||
| 3256 | EMACS_INT minus_count_min = min (-MOST_NEGATIVE_FIXNUM, | ||
| 3257 | TYPE_MAXIMUM (mp_bitcnt_t)); | ||
| 3258 | CHECK_INTEGER (value); | 3254 | CHECK_INTEGER (value); |
| 3259 | CHECK_RANGED_INTEGER (count, - minus_count_min, TYPE_MAXIMUM (mp_bitcnt_t)); | 3255 | CHECK_INTEGER (count); |
| 3256 | |||
| 3257 | if (! FIXNUMP (count)) | ||
| 3258 | { | ||
| 3259 | if (EQ (value, make_fixnum (0))) | ||
| 3260 | return value; | ||
| 3261 | if (mpz_sgn (XBIGNUM (count)->value) < 0) | ||
| 3262 | { | ||
| 3263 | EMACS_INT v = (FIXNUMP (value) ? XFIXNUM (value) | ||
| 3264 | : mpz_sgn (XBIGNUM (value)->value)); | ||
| 3265 | return make_fixnum (v < 0 ? -1 : 0); | ||
| 3266 | } | ||
| 3267 | overflow_error (); | ||
| 3268 | } | ||
| 3260 | 3269 | ||
| 3261 | if (XFIXNUM (count) <= 0) | 3270 | if (XFIXNUM (count) <= 0) |
| 3262 | { | 3271 | { |
| @@ -3275,7 +3284,11 @@ In this case, the sign bit is duplicated. */) | |||
| 3275 | 3284 | ||
| 3276 | mpz_t *zval = bignum_integer (&mpz[0], value); | 3285 | mpz_t *zval = bignum_integer (&mpz[0], value); |
| 3277 | if (XFIXNUM (count) < 0) | 3286 | if (XFIXNUM (count) < 0) |
| 3278 | mpz_fdiv_q_2exp (mpz[0], *zval, - XFIXNUM (count)); | 3287 | { |
| 3288 | if (TYPE_MAXIMUM (mp_bitcnt_t) < - XFIXNUM (count)) | ||
| 3289 | return make_fixnum (mpz_sgn (*zval) < 0 ? -1 : 0); | ||
| 3290 | mpz_fdiv_q_2exp (mpz[0], *zval, - XFIXNUM (count)); | ||
| 3291 | } | ||
| 3279 | else | 3292 | else |
| 3280 | emacs_mpz_mul_2exp (mpz[0], *zval, XFIXNUM (count)); | 3293 | emacs_mpz_mul_2exp (mpz[0], *zval, XFIXNUM (count)); |
| 3281 | return make_integer_mpz (); | 3294 | return make_integer_mpz (); |
diff --git a/test/src/data-tests.el b/test/src/data-tests.el index d41c7623289..bbf7e2a2394 100644 --- a/test/src/data-tests.el +++ b/test/src/data-tests.el | |||
| @@ -656,6 +656,10 @@ comparing the subr with a much slower lisp implementation." | |||
| 656 | (ert-deftest data-tests-ash-lsh () | 656 | (ert-deftest data-tests-ash-lsh () |
| 657 | (should (= (ash most-negative-fixnum 1) | 657 | (should (= (ash most-negative-fixnum 1) |
| 658 | (* most-negative-fixnum 2))) | 658 | (* most-negative-fixnum 2))) |
| 659 | (should (= (ash 0 (* 2 most-positive-fixnum)) 0)) | ||
| 660 | (should (= (ash 1000 (* 2 most-negative-fixnum)) 0)) | ||
| 661 | (should (= (ash -1000 (* 2 most-negative-fixnum)) -1)) | ||
| 662 | (should (= (ash (* 2 most-negative-fixnum) (* 2 most-negative-fixnum)) -1)) | ||
| 659 | (should (= (lsh most-negative-fixnum 1) | 663 | (should (= (lsh most-negative-fixnum 1) |
| 660 | (* most-negative-fixnum 2))) | 664 | (* most-negative-fixnum 2))) |
| 661 | (should (= (ash (* 2 most-negative-fixnum) -1) | 665 | (should (= (ash (* 2 most-negative-fixnum) -1) |