mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 03:30:27 +02:00
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.
This commit is contained in:
parent
8b99ace658
commit
fc4228c196
3 changed files with 42 additions and 33 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue