1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

Implement scm_logcount with new integer library

* libguile/integers.c (scm_integer_logcount_i)
(scm_integer_logcount_z): New internal functions.
* libguile/integers.h: Declare the new internal functions.
* libguile/numbers.c (scm_logcount): Use new internal functions.
This commit is contained in:
Andy Wingo 2022-01-04 09:53:09 +01:00
parent 88f56e91aa
commit 7ec40fe5b0
3 changed files with 42 additions and 32 deletions

View file

@ -2254,3 +2254,40 @@ scm_integer_bit_extract_z (SCM n, unsigned long start, unsigned long bits)
scm_remember_upto_here_1 (n);
return take_mpz (result);
}
static const char scm_logtab[] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
};
SCM
scm_integer_logcount_i (scm_t_inum n)
{
unsigned long c = 0;
if (n < 0)
n = -1 - n;
while (n)
{
c += scm_logtab[15 & n];
n >>= 4;
}
return SCM_I_MAKINUM (c);
}
SCM
scm_integer_logcount_z (SCM n)
{
unsigned long count;
mpz_t zn;
alias_bignum_to_mpz (scm_bignum (n), zn);
if (mpz_sgn (zn) >= 0)
count = mpz_popcount (zn);
else
{
mpz_t z_negative_one;
mpz_init_set_si (z_negative_one, -1);
count = mpz_hamdist (zn, z_negative_one);
mpz_clear (z_negative_one);
}
scm_remember_upto_here_1 (n);
return scm_from_ulong (count);
}

View file

@ -168,6 +168,9 @@ SCM_INTERNAL SCM scm_integer_bit_extract_i (scm_t_inum n, unsigned long start,
SCM_INTERNAL SCM scm_integer_bit_extract_z (SCM n, unsigned long start,
unsigned long bits);
SCM_INTERNAL SCM scm_integer_logcount_i (scm_t_inum n);
SCM_INTERNAL SCM scm_integer_logcount_z (SCM n);
#endif /* SCM_INTEGERS_H */

View file

@ -234,10 +234,6 @@ scm_from_complex_double (complex double z)
static mpz_t z_negative_one;
/* Clear the `mpz_t' embedded in bignum PTR. */
static void
finalize_bignum (void *ptr, void *data)
@ -3369,11 +3365,6 @@ SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
}
#undef FUNC_NAME
static const char scm_logtab[] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
};
SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
(SCM n),
"Return the number of bits in integer @var{n}. If integer is\n"
@ -3392,28 +3383,9 @@ SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
#define FUNC_NAME s_scm_logcount
{
if (SCM_I_INUMP (n))
{
unsigned long c = 0;
scm_t_inum nn = SCM_I_INUM (n);
if (nn < 0)
nn = -1 - nn;
while (nn)
{
c += scm_logtab[15 & nn];
nn >>= 4;
}
return SCM_I_MAKINUM (c);
}
return scm_integer_logcount_i (SCM_I_INUM (n));
else if (SCM_BIGP (n))
{
unsigned long count;
if (mpz_sgn (SCM_I_BIG_MPZ (n)) >= 0)
count = mpz_popcount (SCM_I_BIG_MPZ (n));
else
count = mpz_hamdist (SCM_I_BIG_MPZ (n), z_negative_one);
scm_remember_upto_here_1 (n);
return SCM_I_MAKINUM (count);
}
return scm_integer_logcount_z (n);
else
SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
}
@ -8527,8 +8499,6 @@ scm_init_numbers ()
custom_gmp_realloc,
custom_gmp_free);
mpz_init_set_si (z_negative_one, -1);
/* It may be possible to tune the performance of some algorithms by using
* the following constants to avoid the creation of bignums. Please, before
* using these values, remember the two rules of program optimization: