summaryrefslogtreecommitdiff
path: root/libguile
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2022-01-10 11:12:36 +0100
committerAndy Wingo <wingo@pobox.com>2022-01-13 09:37:17 +0100
commit6fe43301aa66f898f3b27d604c45c93da5286e12 (patch)
tree6260161c1df3d4e6c37b1c588ce6b3e9d0d24bed /libguile
parent2cf80ca2383f2c0e0a4171296e136cfcc579eeb2 (diff)
downloadguile-6fe43301aa66f898f3b27d604c45c93da5286e12.tar.gz
Optimize integer-expt for fixnums
* libguile/integers.c (scm_integer_expt_ii): Add some optimizations for cases in which we can avoid allocating an mpz.
Diffstat (limited to 'libguile')
-rw-r--r--libguile/integers.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/libguile/integers.c b/libguile/integers.c
index de1d2b3d5..a173d01f2 100644
--- a/libguile/integers.c
+++ b/libguile/integers.c
@@ -2265,6 +2265,27 @@ SCM
scm_integer_expt_ii (scm_t_inum n, scm_t_inum k)
{
ASSERT (k >= 0);
+ if (k == 0)
+ return SCM_INUM1;
+ if (k == 1)
+ return SCM_I_MAKINUM (n);
+ if (n == -1)
+ return scm_is_integer_odd_i (k) ? SCM_I_MAKINUM (-1) : SCM_INUM1;
+ if (n == 2)
+ {
+ if (k < SCM_I_FIXNUM_BIT - 1)
+ return SCM_I_MAKINUM (1L << k);
+ if (k < 64)
+ return scm_integer_from_uint64 (((uint64_t) 1) << k);
+ size_t nlimbs = k / (sizeof (mp_limb_t)*8) + 1;
+ size_t high_shift = k & (sizeof (mp_limb_t)*8 - 1);
+ struct scm_bignum *result = allocate_bignum (nlimbs);
+ mp_limb_t *rd = bignum_limbs (result);
+ mpn_zero(rd, nlimbs - 1);
+ rd[nlimbs - 1] = ((mp_limb_t) 1) << high_shift;
+ return scm_from_bignum (result);
+ }
+
mpz_t res;
mpz_init (res);
mpz_ui_pow_ui (res, inum_magnitude (n), k);