diff options
| author | Paul Eggert | 2019-11-13 12:10:31 -0800 |
|---|---|---|
| committer | Paul Eggert | 2019-11-13 13:10:09 -0800 |
| commit | 02e637ecca3b1419d2a6c433eca72c5728c65051 (patch) | |
| tree | f3a213c730c7893513a69b5f9e2e69a429f837da /src/data.c | |
| parent | ff10e9517d98aa606e007d3aa4d5aef1c423ab77 (diff) | |
| download | emacs-02e637ecca3b1419d2a6c433eca72c5728c65051.tar.gz emacs-02e637ecca3b1419d2a6c433eca72c5728c65051.zip | |
Refactor bignum multiplication, exponentiation
This doesn’t alter behavior, and simplifies the next commit.
* src/bignum.c (GMP_NLIMBS_MAX, NLIMBS_LIMIT, emacs_mpz_size)
(emacs_mpz_mul, emacs_mpz_mul_2exp, emacs_mpz_pow_ui): Move here ...
* src/data.c: ... from here.
Diffstat (limited to 'src/data.c')
| -rw-r--r-- | src/data.c | 74 |
1 files changed, 0 insertions, 74 deletions
diff --git a/src/data.c b/src/data.c index 649dc174f90..9efcd72f93e 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -2352,80 +2352,6 @@ bool-vector. IDX starts at 0. */) | |||
| 2352 | return newelt; | 2352 | return newelt; |
| 2353 | } | 2353 | } |
| 2354 | 2354 | ||
| 2355 | /* GMP tests for this value and aborts (!) if it is exceeded. | ||
| 2356 | This is as of GMP 6.1.2 (2016); perhaps future versions will differ. */ | ||
| 2357 | enum { GMP_NLIMBS_MAX = min (INT_MAX, ULONG_MAX / GMP_NUMB_BITS) }; | ||
| 2358 | |||
| 2359 | /* An upper bound on limb counts, needed to prevent libgmp and/or | ||
| 2360 | Emacs from aborting or otherwise misbehaving. This bound applies | ||
| 2361 | to estimates of mpz_t sizes before the mpz_t objects are created, | ||
| 2362 | as opposed to integer-width which operates on mpz_t values after | ||
| 2363 | creation and before conversion to Lisp bignums. */ | ||
| 2364 | enum | ||
| 2365 | { | ||
| 2366 | NLIMBS_LIMIT = min (min (/* libgmp needs to store limb counts. */ | ||
| 2367 | GMP_NLIMBS_MAX, | ||
| 2368 | |||
| 2369 | /* Size calculations need to work. */ | ||
| 2370 | min (PTRDIFF_MAX, SIZE_MAX) / sizeof (mp_limb_t)), | ||
| 2371 | |||
| 2372 | /* Emacs puts bit counts into fixnums. */ | ||
| 2373 | MOST_POSITIVE_FIXNUM / GMP_NUMB_BITS) | ||
| 2374 | }; | ||
| 2375 | |||
| 2376 | /* Like mpz_size, but tell the compiler the result is a nonnegative int. */ | ||
| 2377 | |||
| 2378 | static int | ||
| 2379 | emacs_mpz_size (mpz_t const op) | ||
| 2380 | { | ||
| 2381 | mp_size_t size = mpz_size (op); | ||
| 2382 | eassume (0 <= size && size <= INT_MAX); | ||
| 2383 | return size; | ||
| 2384 | } | ||
| 2385 | |||
| 2386 | /* Wrappers to work around GMP limitations. As of GMP 6.1.2 (2016), | ||
| 2387 | the library code aborts when a number is too large. These wrappers | ||
| 2388 | avoid the problem for functions that can return numbers much larger | ||
| 2389 | than their arguments. For slowly-growing numbers, the integer | ||
| 2390 | width checks in bignum.c should suffice. */ | ||
| 2391 | |||
| 2392 | static void | ||
| 2393 | emacs_mpz_mul (mpz_t rop, mpz_t const op1, mpz_t const op2) | ||
| 2394 | { | ||
| 2395 | if (NLIMBS_LIMIT - emacs_mpz_size (op1) < emacs_mpz_size (op2)) | ||
| 2396 | overflow_error (); | ||
| 2397 | mpz_mul (rop, op1, op2); | ||
| 2398 | } | ||
| 2399 | |||
| 2400 | static void | ||
| 2401 | emacs_mpz_mul_2exp (mpz_t rop, mpz_t const op1, EMACS_INT op2) | ||
| 2402 | { | ||
| 2403 | /* Fudge factor derived from GMP 6.1.2, to avoid an abort in | ||
| 2404 | mpz_mul_2exp (look for the '+ 1' in its source code). */ | ||
| 2405 | enum { mul_2exp_extra_limbs = 1 }; | ||
| 2406 | enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - mul_2exp_extra_limbs) }; | ||
| 2407 | |||
| 2408 | EMACS_INT op2limbs = op2 / GMP_NUMB_BITS; | ||
| 2409 | if (lim - emacs_mpz_size (op1) < op2limbs) | ||
| 2410 | overflow_error (); | ||
| 2411 | mpz_mul_2exp (rop, op1, op2); | ||
| 2412 | } | ||
| 2413 | |||
| 2414 | static void | ||
| 2415 | emacs_mpz_pow_ui (mpz_t rop, mpz_t const base, unsigned long exp) | ||
| 2416 | { | ||
| 2417 | /* This fudge factor is derived from GMP 6.1.2, to avoid an abort in | ||
| 2418 | mpz_n_pow_ui (look for the '5' in its source code). */ | ||
| 2419 | enum { pow_ui_extra_limbs = 5 }; | ||
| 2420 | enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - pow_ui_extra_limbs) }; | ||
| 2421 | |||
| 2422 | int nbase = emacs_mpz_size (base), n; | ||
| 2423 | if (INT_MULTIPLY_WRAPV (nbase, exp, &n) || lim < n) | ||
| 2424 | overflow_error (); | ||
| 2425 | mpz_pow_ui (rop, base, exp); | ||
| 2426 | } | ||
| 2427 | |||
| 2428 | |||
| 2429 | /* Arithmetic functions */ | 2355 | /* Arithmetic functions */ |
| 2430 | 2356 | ||
| 2431 | Lisp_Object | 2357 | Lisp_Object |