mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +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);
|
scm_remember_upto_here_1 (n);
|
||||||
return scm_from_ulong (count);
|
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
|
#ifndef SCM_INTEGERS_H
|
||||||
#define 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.
|
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_i (scm_t_inum n);
|
||||||
SCM_INTERNAL SCM scm_integer_logcount_z (struct scm_bignum *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 */
|
#endif /* SCM_INTEGERS_H */
|
||||||
|
|
|
@ -3409,12 +3409,6 @@ SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#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_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
|
||||||
(SCM n),
|
(SCM n),
|
||||||
"Return the number of bits necessary to represent @var{n}.\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
|
#define FUNC_NAME s_scm_integer_length
|
||||||
{
|
{
|
||||||
if (SCM_I_INUMP (n))
|
if (SCM_I_INUMP (n))
|
||||||
{
|
return scm_integer_length_i (SCM_I_INUM (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);
|
|
||||||
}
|
|
||||||
else if (SCM_BIGP (n))
|
else if (SCM_BIGP (n))
|
||||||
{
|
return scm_integer_length_z (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. */
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
|
SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue