diff options
author | Andy Wingo <wingo@pobox.com> | 2022-01-06 11:10:02 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2022-01-13 09:37:16 +0100 |
commit | f4db3ca3f9986477f6a8d4eddae8b88604e3f8a9 (patch) | |
tree | a289ceae1d4d36d90ba070c15efaddc34ffee7b3 /libguile/numbers.c | |
parent | 7c53325c31b86198b6c021c5c2b62c3742363619 (diff) | |
download | guile-f4db3ca3f9986477f6a8d4eddae8b88604e3f8a9.tar.gz |
Reimplement scm_is_{un,}signed_integer for bignums
* libguile/integers.c (negative_int64):
(int64_magnitude):
(negative_uint64_to_int64):
(positive_uint64_to_int64):
(bignum_to_int64):
(bignum_to_uint64): New helpers.
(scm_integer_to_int64_z):
(scm_integer_to_uint64_z): New internal functions.
* libguile/integers.h: Declare internal functions.
* libguile/numbers.c (scm_is_signed_integer):
(scm_is_unsigned_integer): Simplify bigint cases.
Diffstat (limited to 'libguile/numbers.c')
-rw-r--r-- | libguile/numbers.c | 87 |
1 files changed, 13 insertions, 74 deletions
diff --git a/libguile/numbers.c b/libguile/numbers.c index 549b730ec..8657a6ebe 100644 --- a/libguile/numbers.c +++ b/libguile/numbers.c @@ -6788,59 +6788,24 @@ scm_is_exact_integer (SCM val) return SCM_I_INUMP (val) || SCM_BIGP (val); } +// Given that there is no way to extend intmax_t to encompass types +// larger than int64, and that we must have int64, intmax will always be +// 8 bytes wide, and we can treat intmax arguments as int64's. +verify(SCM_SIZEOF_INTMAX == 8); + int scm_is_signed_integer (SCM val, intmax_t min, intmax_t max) { if (SCM_I_INUMP (val)) { scm_t_signed_bits n = SCM_I_INUM (val); - return n >= min && n <= max; + return min <= n && n <= max; } else if (SCM_BIGP (val)) { - if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM) - return 0; - else if (min >= LONG_MIN && max <= LONG_MAX) - { - if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val))) - { - long n = mpz_get_si (SCM_I_BIG_MPZ (val)); - return n >= min && n <= max; - } - else - return 0; - } - else - { - uintmax_t abs_n; - intmax_t n; - size_t count; - - if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2) - > CHAR_BIT*sizeof (uintmax_t)) - return 0; - - mpz_export (&abs_n, &count, 1, sizeof (uintmax_t), 0, 0, - SCM_I_BIG_MPZ (val)); - - if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0) - { - if (abs_n <= max) - n = abs_n; - else - return 0; - } - else - { - /* Carefully avoid signed integer overflow. */ - if (min < 0 && abs_n - 1 <= -(min + 1)) - n = -1 - (intmax_t)(abs_n - 1); - else - return 0; - } - - return n >= min && n <= max; - } + int64_t n; + return scm_integer_to_int64_z (scm_bignum (val), &n) + && min <= n && n <= max; } else return 0; @@ -6856,35 +6821,9 @@ scm_is_unsigned_integer (SCM val, uintmax_t min, uintmax_t max) } else if (SCM_BIGP (val)) { - if (max <= SCM_MOST_POSITIVE_FIXNUM) - return 0; - else if (max <= ULONG_MAX) - { - if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val))) - { - unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val)); - return n >= min && n <= max; - } - else - return 0; - } - else - { - uintmax_t n; - size_t count; - - if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0) - return 0; - - if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2) - > CHAR_BIT*sizeof (uintmax_t)) - return 0; - - mpz_export (&n, &count, 1, sizeof (uintmax_t), 0, 0, - SCM_I_BIG_MPZ (val)); - - return n >= min && n <= max; - } + uint64_t n; + return scm_integer_to_uint64_z (scm_bignum (val), &n) + && min <= n && n <= max; } else return 0; @@ -6895,7 +6834,7 @@ scm_i_range_error (SCM bad_val, SCM min, SCM max) { scm_error (scm_out_of_range_key, NULL, - "Value out of range ~S to ~S: ~S", + "Value out of range ~S to< ~S: ~S", scm_list_3 (min, max, bad_val), scm_list_1 (bad_val)); } |