[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Guile-commits] 49/69: Reimplement scm_is_{un, }signed_integer for bignu
From: |
Andy Wingo |
Subject: |
[Guile-commits] 49/69: Reimplement scm_is_{un, }signed_integer for bignums |
Date: |
Fri, 7 Jan 2022 08:27:14 -0500 (EST) |
wingo pushed a commit to branch wip-inline-digits
in repository guile.
commit 3b4b722ff4646049a316f30916433c554d482c20
Author: Andy Wingo <wingo@pobox.com>
AuthorDate: Thu Jan 6 11:10:02 2022 +0100
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.
---
libguile/integers.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++
libguile/integers.h | 3 ++
libguile/numbers.c | 87 +++++++------------------------------------
3 files changed, 120 insertions(+), 74 deletions(-)
diff --git a/libguile/integers.c b/libguile/integers.c
index 2e35bc2d5..b8cb1a908 100644
--- a/libguile/integers.c
+++ b/libguile/integers.c
@@ -25,6 +25,7 @@
#include <math.h>
#include <stdlib.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <verify.h>
@@ -115,6 +116,22 @@ negative_long (unsigned long mag)
return ~mag + 1;
}
+static inline int64_t
+negative_int64 (uint64_t mag)
+{
+ ASSERT (mag <= (uint64_t) INT64_MIN);
+ return ~mag + 1;
+}
+
+static inline uint64_t
+int64_magnitude (int64_t i)
+{
+ uint64_t mag = i;
+ if (i < 0)
+ mag = ~mag + 1;
+ return mag;
+}
+
static inline scm_t_bits
inum_magnitude (scm_t_inum i)
{
@@ -266,6 +283,82 @@ long_sign (long l)
return 1;
}
+static int
+negative_uint64_to_int64 (uint64_t magnitude, int64_t *val)
+{
+ if (magnitude > int64_magnitude (INT64_MIN))
+ return 0;
+ *val = negative_int64 (magnitude);
+ return 1;
+}
+
+static int
+positive_uint64_to_int64 (uint64_t magnitude, int64_t *val)
+{
+ if (magnitude > INT64_MAX)
+ return 0;
+ *val = magnitude;
+ return 1;
+}
+
+static int
+bignum_to_int64 (struct scm_bignum *z, int64_t *val)
+{
+ switch (bignum_size (z))
+ {
+#if SCM_SIZEOF_LONG == 4
+ case -2:
+ {
+ uint64_t mag = bignum_limbs (z)[0];
+ mag |= ((uint64_t) bignum_limbs (z)[1]) << 32;
+ return negative_uint64_to_int64 (mag, val);
+ }
+#endif
+ case -1:
+ return negative_uint64_to_int64 (bignum_limbs (z)[0], val);
+ case 0:
+ *val = 0;
+ return 1;
+ case 1:
+ return positive_uint64_to_int64 (bignum_limbs (z)[0], val);
+#if SCM_SIZEOF_LONG == 4
+ case 2:
+ {
+ uint64_t mag = bignum_limbs (z)[0];
+ mag |= ((uint64_t) bignum_limbs (z)[1]) << 32;
+ return positive_uint64_to_int64 (mag, val);
+ }
+#endif
+ default:
+ return 0;
+ }
+}
+
+static int
+bignum_to_uint64 (struct scm_bignum *z, uint64_t *val)
+{
+ switch (bignum_size (z))
+ {
+ case 0:
+ *val = 0;
+ return 1;
+ case 1:
+ *val = bignum_limbs (z)[0];
+ return 1;
+#if SCM_SIZEOF_LONG == 4
+ case 2:
+ {
+ uint64_t mag = bignum_limbs (z)[0];
+ mag |= ((uint64_t) bignum_limbs (z)[1]) << 32;
+ *val = mag;
+ return 1;
+ }
+#endif
+ default:
+ return 0;
+ }
+}
+
static int
bignum_cmp_long (struct scm_bignum *z, long l)
{
@@ -2803,3 +2896,14 @@ scm_integer_exact_quotient_zz (struct scm_bignum *n,
struct scm_bignum *d)
return take_mpz (q);
}
+int
+scm_integer_to_int64_z (struct scm_bignum *z, int64_t *val)
+{
+ return bignum_to_int64 (z, val);
+}
+
+int
+scm_integer_to_uint64_z (struct scm_bignum *z, uint64_t *val)
+{
+ return bignum_to_uint64 (z, val);
+}
diff --git a/libguile/integers.h b/libguile/integers.h
index bda575774..60e3ea9bd 100644
--- a/libguile/integers.h
+++ b/libguile/integers.h
@@ -199,6 +199,9 @@ SCM_INTERNAL SCM scm_integer_exact_quotient_zi (struct
scm_bignum *n,
SCM_INTERNAL SCM scm_integer_exact_quotient_zz (struct scm_bignum *n,
struct scm_bignum *d);
+SCM_INTERNAL int scm_integer_to_int64_z (struct scm_bignum *z, int64_t *val);
+SCM_INTERNAL int scm_integer_to_uint64_z (struct scm_bignum *z, uint64_t *val);
+
#endif /* SCM_INTEGERS_H */
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));
}
- [Guile-commits] 42/69: Clean up scm_sum, (continued)
- [Guile-commits] 42/69: Clean up scm_sum, Andy Wingo, 2022/01/07
- [Guile-commits] 43/69: Simplify scm_difference, use integer lib, Andy Wingo, 2022/01/07
- [Guile-commits] 44/69: Simplify scm_product, use integer lib, Andy Wingo, 2022/01/07
- [Guile-commits] 52/69: Reimplement scm_{to,from}_{int64,uint64}, Andy Wingo, 2022/01/07
- [Guile-commits] 53/69: Implement scm_{to,from}_wchar inline, Andy Wingo, 2022/01/07
- [Guile-commits] 60/69: divide2double refactor, Andy Wingo, 2022/01/07
- [Guile-commits] 65/69: Avoid scm_i_mkbig outside numbers.c., Andy Wingo, 2022/01/07
- [Guile-commits] 57/69: Refactor scm_sqrt in terms of integers.[ch], Andy Wingo, 2022/01/07
- [Guile-commits] 59/69: Remove dead bignum frexp code from numbers.c, Andy Wingo, 2022/01/07
- [Guile-commits] 47/69: Fix deprecated bit-count* when counting 0 bits, Andy Wingo, 2022/01/07
- [Guile-commits] 49/69: Reimplement scm_is_{un, }signed_integer for bignums,
Andy Wingo <=
- [Guile-commits] 51/69: Reimplement scm_{to,from}_{int32,uint32}, Andy Wingo, 2022/01/07
- [Guile-commits] 45/69: Remove support for allowing exact numbers to be divided by zero, Andy Wingo, 2022/01/07
- [Guile-commits] 50/69: Reimplement scm_from_int8 etc, Andy Wingo, 2022/01/07
- [Guile-commits] 56/69: Reimplement exact-integer-sqrt with integers.[ch], Andy Wingo, 2022/01/07
- [Guile-commits] 55/69: scm_to_mpz uses integer lib, Andy Wingo, 2022/01/07
- [Guile-commits] 62/69: Remove last non-admin SCM_I_BIG_MPZ uses in numbers.c, Andy Wingo, 2022/01/07
- [Guile-commits] 61/69: Simplify scm_exact_integer_quotient, Andy Wingo, 2022/01/07
- [Guile-commits] 63/69: Simplify magnitude, angle, Andy Wingo, 2022/01/07
- [Guile-commits] 64/69: Use scm_integer_to_double_z in numbers.c instead of big2dbl, Andy Wingo, 2022/01/07
- [Guile-commits] 67/69: Finish srfi-60 port off old scm mpz API, Andy Wingo, 2022/01/07