diff options
author | Andy Wingo <wingo@pobox.com> | 2022-01-09 14:39:42 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2022-01-13 09:37:17 +0100 |
commit | d89f75c5355139da67d019bf3073fda095678ed7 (patch) | |
tree | b718ef1cd240dd3833cbc4991265c75c76b32aae /libguile/integers.c | |
parent | 548122267075817bcd894ac5e88b1fded30d58f3 (diff) | |
download | guile-d89f75c5355139da67d019bf3073fda095678ed7.tar.gz |
Optimize scm_integer_mul_zi
* libguile/integers.c (bignum_trim1):
(bignum_negate_if): New helpers.
(scm_integer_mul_zi): Use the mpn API to avoid temporary allocation.
Diffstat (limited to 'libguile/integers.c')
-rw-r--r-- | libguile/integers.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/libguile/integers.c b/libguile/integers.c index 143683738..ee2907f30 100644 --- a/libguile/integers.c +++ b/libguile/integers.c @@ -168,6 +168,14 @@ allocate_bignum (size_t nlimbs) } static struct scm_bignum * +bignum_trim1 (struct scm_bignum *z) +{ + ASSERT (z->u.z.size > 0); + z->u.z.size -= (z->limbs[z->u.z.size - 1] == 0); + return z; +} + +static struct scm_bignum * negate_bignum (struct scm_bignum *z) { z->u.z.size = -z->u.z.size; @@ -175,6 +183,12 @@ negate_bignum (struct scm_bignum *z) } static struct scm_bignum * +bignum_negate_if (int negate, struct scm_bignum *z) +{ + return negate ? negate_bignum (z) : z; +} + +static struct scm_bignum * make_bignum_0 (void) { return allocate_bignum (0); @@ -2906,12 +2920,18 @@ scm_integer_mul_zi (struct scm_bignum *x, scm_t_inum y) return scm_from_bignum (x); default: { - mpz_t result, zx; - mpz_init (result); - alias_bignum_to_mpz (x, zx); - mpz_mul_si (result, zx, y); + size_t xn = bignum_limb_count (x); + if (xn == 0) + return SCM_INUM0; + + struct scm_bignum *result = allocate_bignum (xn + 1); + const mp_limb_t *xd = bignum_limbs (x); + mp_limb_t yd[1] = { long_magnitude (y) }; + int negate = bignum_is_negative (x) != (y < 0); + mpn_mul (bignum_limbs (result), xd, xn, yd, 1); scm_remember_upto_here_1 (x); - return take_mpz (result); + return normalize_bignum + (bignum_negate_if (negate, (bignum_trim1 (result)))); } } } |