summaryrefslogtreecommitdiff
path: root/libguile/integers.c
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2022-01-09 16:46:27 +0100
committerAndy Wingo <wingo@pobox.com>2022-01-13 09:37:17 +0100
commitad6811a12b8a3aab68d0610c799c51515ec7c427 (patch)
treee71dd2185d64450ada56bd0cbe8caeb47d3e37d9 /libguile/integers.c
parentd89f75c5355139da67d019bf3073fda095678ed7 (diff)
downloadguile-ad6811a12b8a3aab68d0610c799c51515ec7c427.tar.gz
Optimize scm_integer_mul_zz.
* libguile/integers.c (scm_integer_mul_zz): Optimize to avoid temporary allocations.
Diffstat (limited to 'libguile/integers.c')
-rw-r--r--libguile/integers.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/libguile/integers.c b/libguile/integers.c
index ee2907f30..60c0fd34a 100644
--- a/libguile/integers.c
+++ b/libguile/integers.c
@@ -2939,13 +2939,25 @@ scm_integer_mul_zi (struct scm_bignum *x, scm_t_inum y)
SCM
scm_integer_mul_zz (struct scm_bignum *x, struct scm_bignum *y)
{
- mpz_t result, zx, zy;
- mpz_init (result);
- alias_bignum_to_mpz (x, zx);
- alias_bignum_to_mpz (y, zy);
- mpz_mul (result, zx, zy);
+ size_t xn = bignum_limb_count (x);
+ size_t yn = bignum_limb_count (y);
+ if (xn == 0 || yn == 0)
+ return SCM_INUM0;
+
+ struct scm_bignum *result = allocate_bignum (xn + yn);
+ mp_limb_t *rd = bignum_limbs (result);
+ const mp_limb_t *xd = bignum_limbs (x);
+ const mp_limb_t *yd = bignum_limbs (y);
+ int negate = bignum_is_negative (x) != bignum_is_negative (y);
+ if (xd == yd)
+ mpn_sqr (rd, xd, xn);
+ else if (xn <= yn)
+ mpn_mul (rd, yd, yn, xd, xn);
+ else
+ mpn_mul (rd, xd, xn, yd, yn);
scm_remember_upto_here_2 (x, y);
- return take_mpz (result);
+ return normalize_bignum
+ (bignum_negate_if (negate, (bignum_trim1 (result))));
}
int