summaryrefslogtreecommitdiff
path: root/libguile/integers.c
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2022-01-09 14:39:42 +0100
committerAndy Wingo <wingo@pobox.com>2022-01-13 09:37:17 +0100
commitd89f75c5355139da67d019bf3073fda095678ed7 (patch)
treeb718ef1cd240dd3833cbc4991265c75c76b32aae /libguile/integers.c
parent548122267075817bcd894ac5e88b1fded30d58f3 (diff)
downloadguile-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.c30
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))));
}
}
}