From fc4228c1967fc7c3cb7e408c202c526cfe04f237 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Tue, 4 Jan 2022 10:51:20 +0100 Subject: [PATCH] Implement scm_integer_length with new integer library * libguile/integers.c (scm_integer_length_i) (scm_integer_length_z): New internal functions. * libguile/integers.h: Declare the new internal functions. * libguile/numbers.c (scm_integer_length): Use new internal functions. --- libguile/integers.c | 36 ++++++++++++++++++++++++++++++++++++ libguile/integers.h | 5 ++++- libguile/numbers.c | 34 ++-------------------------------- 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/libguile/integers.c b/libguile/integers.c index db806b35f..fafef184f 100644 --- a/libguile/integers.c +++ b/libguile/integers.c @@ -2291,3 +2291,39 @@ scm_integer_logcount_z (struct scm_bignum *n) scm_remember_upto_here_1 (n); return scm_from_ulong (count); } + +static const char scm_ilentab[] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 +}; + +SCM +scm_integer_length_i (scm_t_inum n) +{ + unsigned long c = 0; + unsigned int l = 4; + if (n < 0) + n = -1 - n; + while (n) + { + c += 4; + l = scm_ilentab [15 & n]; + n >>= 4; + } + return SCM_I_MAKINUM (c - 4 + l); +} + +SCM +scm_integer_length_z (struct scm_bignum *n) +{ + /* mpz_sizeinbase looks at the absolute value of negatives, whereas we + want a ones-complement. If n is ...111100..00 then mpz_sizeinbase is + 1 too big, so check for that and adjust. */ + mpz_t zn; + alias_bignum_to_mpz (n, zn); + size_t size = mpz_sizeinbase (zn, 2); + /* If negative and no 0 bits above the lowest 1, adjust result. */ + if (mpz_sgn (zn) < 0 && mpz_scan0 (zn, mpz_scan1 (zn, 0)) == ULONG_MAX) + size--; + scm_remember_upto_here_1 (n); + return scm_from_size_t (size); +} diff --git a/libguile/integers.h b/libguile/integers.h index 0ffe713a1..5bc2c7650 100644 --- a/libguile/integers.h +++ b/libguile/integers.h @@ -1,7 +1,7 @@ #ifndef SCM_INTEGERS_H #define SCM_INTEGERS_H -/* Copyright 2021 Free Software Foundation, Inc. +/* Copyright 2021, 2022 Free Software Foundation, Inc. This file is part of Guile. @@ -141,6 +141,9 @@ SCM_INTERNAL SCM scm_integer_bit_extract_z (struct scm_bignum *n, SCM_INTERNAL SCM scm_integer_logcount_i (scm_t_inum n); SCM_INTERNAL SCM scm_integer_logcount_z (struct scm_bignum *n); +SCM_INTERNAL SCM scm_integer_length_i (scm_t_inum n); +SCM_INTERNAL SCM scm_integer_length_z (struct scm_bignum *n); + #endif /* SCM_INTEGERS_H */ diff --git a/libguile/numbers.c b/libguile/numbers.c index 1a840e424..efc9ed06c 100644 --- a/libguile/numbers.c +++ b/libguile/numbers.c @@ -3409,12 +3409,6 @@ SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0, } #undef FUNC_NAME - -static const char scm_ilentab[] = { - 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 -}; - - SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0, (SCM n), "Return the number of bits necessary to represent @var{n}.\n" @@ -3430,33 +3424,9 @@ SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0, #define FUNC_NAME s_scm_integer_length { if (SCM_I_INUMP (n)) - { - unsigned long c = 0; - unsigned int l = 4; - scm_t_inum nn = SCM_I_INUM (n); - if (nn < 0) - nn = -1 - nn; - while (nn) - { - c += 4; - l = scm_ilentab [15 & nn]; - nn >>= 4; - } - return SCM_I_MAKINUM (c - 4 + l); - } + return scm_integer_length_i (SCM_I_INUM (n)); else if (SCM_BIGP (n)) - { - /* mpz_sizeinbase looks at the absolute value of negatives, whereas we - want a ones-complement. If n is ...111100..00 then mpz_sizeinbase is - 1 too big, so check for that and adjust. */ - size_t size = mpz_sizeinbase (SCM_I_BIG_MPZ (n), 2); - if (mpz_sgn (SCM_I_BIG_MPZ (n)) < 0 - && mpz_scan0 (SCM_I_BIG_MPZ (n), /* no 0 bits above the lowest 1 */ - mpz_scan1 (SCM_I_BIG_MPZ (n), 0)) == ULONG_MAX) - size--; - scm_remember_upto_here_1 (n); - return SCM_I_MAKINUM (size); - } + return scm_integer_length_z (scm_bignum (n)); else SCM_WRONG_TYPE_ARG (SCM_ARG1, n); }