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); scm_remember_upto_here_1 (n);
return take_mpz (result); 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, SCM_INTERNAL SCM scm_integer_bit_extract_z (SCM n, unsigned long start,
unsigned long bits); 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 */ #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. */ /* Clear the `mpz_t' embedded in bignum PTR. */
static void static void
finalize_bignum (void *ptr, void *data) finalize_bignum (void *ptr, void *data)
@ -3369,11 +3365,6 @@ SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
} }
#undef FUNC_NAME #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_DEFINE (scm_logcount, "logcount", 1, 0, 0,
(SCM n), (SCM n),
"Return the number of bits in integer @var{n}. If integer is\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 #define FUNC_NAME s_scm_logcount
{ {
if (SCM_I_INUMP (n)) if (SCM_I_INUMP (n))
{ return scm_integer_logcount_i (SCM_I_INUM (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);
}
else if (SCM_BIGP (n)) else if (SCM_BIGP (n))
{ return scm_integer_logcount_z (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);
}
else else
SCM_WRONG_TYPE_ARG (SCM_ARG1, n); SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
} }
@ -8527,8 +8499,6 @@ scm_init_numbers ()
custom_gmp_realloc, custom_gmp_realloc,
custom_gmp_free); custom_gmp_free);
mpz_init_set_si (z_negative_one, -1);
/* It may be possible to tune the performance of some algorithms by using /* It may be possible to tune the performance of some algorithms by using
* the following constants to avoid the creation of bignums. Please, before * the following constants to avoid the creation of bignums. Please, before
* using these values, remember the two rules of program optimization: * using these values, remember the two rules of program optimization: