summaryrefslogtreecommitdiffstats
path: root/mpi
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-01-25 06:59:29 -0800
committerKaz Kylheku <kaz@kylheku.com>2019-01-25 06:59:29 -0800
commit4b789435f8e4bb6ec9ea4bab3d0a109682adafa6 (patch)
tree65f91721ae512480ea4df6b9f7f493b35eab6660 /mpi
parent4c71a77f2c39a8158c80b40af1a5cc2358251a00 (diff)
downloadtxr-4b789435f8e4bb6ec9ea4bab3d0a109682adafa6.tar.gz
txr-4b789435f8e4bb6ec9ea4bab3d0a109682adafa6.tar.bz2
txr-4b789435f8e4bb6ec9ea4bab3d0a109682adafa6.zip
Extend infrastructure for double_intptr_t.
We support an unsigned version of the type, and add functions for converting between Lisp values and both types. * arith.c (bignum_dbl_uipt): New function, unsigned companion to existing bignum_dbl_ipt. (c_dbl_num, c_dbl_unum): New functions. * arith.h (bignum_dbl_uipt, c_dbl_num, c_dbl_unum): Declared. * configure (superulong_t, SIZEOF_DOUBLE_INTPTR, DOUBLE_INTPTR_MAX, DOUBLE_INTPTR_MIN, DOUBLE_UINTPTR_MAX, double_uintptr_t): New definitions going into config.h. * lib.h (dbl_cnum, dbl_ucnum): New typedefs: double-sized analogs of cnum and ucnum. * mpi/mpi.c (mp_set_double_uintptr, mp_get_double_uintptr, mp_get_double_intptr): New functions. (s_mp_in_big_range): New static function. (mp_in_double_intptr_range, mp_in_double_uintptr_range): New functions. * mpi/mpi.h (mp_set_double_uintptr, mp_get_double_intptr, mp_get_double_uintptr, mp_in_double_intptr_range, mp_in_double_uintptr_range): Declared.
Diffstat (limited to 'mpi')
-rw-r--r--mpi/mpi.c82
-rw-r--r--mpi/mpi.h5
2 files changed, 86 insertions, 1 deletions
diff --git a/mpi/mpi.c b/mpi/mpi.c
index 2097b574..6aa905bb 100644
--- a/mpi/mpi.c
+++ b/mpi/mpi.c
@@ -471,7 +471,7 @@ mp_err mp_get_intptr(mp_int *mp, int_ptr_t *z)
int mp_in_range(mp_int *mp, uint_ptr_t lim, int unsig)
{
- const int ptrnd = (SIZEOF_PTR + MP_DIGIT_BIT - 1) / MP_DIGIT_BIT;
+ const unsigned ptrnd = (SIZEOF_PTR + MP_DIGIT_BIT - 1) / MP_DIGIT_BIT;
mp_size nd = USED(mp);
if (unsig && ISNEG(mp))
@@ -501,6 +501,7 @@ int mp_in_uintptr_range(mp_int *mp)
}
#ifdef HAVE_DOUBLE_INTPTR_T
+
mp_err mp_set_double_intptr(mp_int *mp, double_intptr_t z)
{
mp_size ix, shift;
@@ -530,6 +531,85 @@ mp_err mp_set_double_intptr(mp_int *mp, double_intptr_t z)
return MP_OKAY;
}
+
+mp_err mp_set_double_uintptr(mp_int *mp, double_uintptr_t v)
+{
+ mp_size ix, shift;
+ const mp_size nd = (sizeof v + sizeof (mp_digit) - 1) / sizeof (mp_digit);
+
+ ARGCHK(mp != NULL, MP_BADARG);
+
+ mp_zero(mp);
+
+ if (v == 0)
+ return MP_OKAY; /* shortcut for zero */
+
+ s_mp_grow(mp, nd);
+
+ USED(mp) = nd;
+
+ for (ix = 0, shift = 0; ix < nd; ix++, shift += MP_DIGIT_BIT)
+ {
+ DIGIT(mp, ix) = (v >> shift) & MP_DIGIT_MAX;
+ }
+
+ s_mp_clamp(mp);
+
+ return MP_OKAY;
+}
+
+mp_err mp_get_double_uintptr(mp_int *mp, double_uintptr_t *z)
+{
+ double_uintptr_t out = 0;
+ mp_size ix;
+ mp_size nd = USED(mp);
+ for (ix = 0; ix < nd; ix++, out <<= MP_DIGIT_BIT)
+ out |= DIGIT(mp, ix);
+
+ *z = (SIGN(mp) == MP_NEG) ? -out : out;
+ return MP_OKAY;
+}
+
+mp_err mp_get_double_intptr(mp_int *mp, double_intptr_t *z)
+{
+ double_uintptr_t tmp = 0;
+ mp_get_double_uintptr(mp, &tmp);
+ /* Reliance on bitwise unsigned to two's complement conversion */
+ *z = convert(int_ptr_t, tmp);
+ return MP_OKAY;
+}
+
+static int s_mp_in_big_range(mp_int *mp, double_uintptr_t lim, int unsig)
+{
+ const unsigned ptrnd = (SIZEOF_DOUBLE_INTPTR + MP_DIGIT_BIT - 1) / MP_DIGIT_BIT;
+ mp_size nd = USED(mp);
+
+ if (unsig && ISNEG(mp))
+ return 0;
+
+ if (nd < ptrnd)
+ return 1;
+
+ if (nd > ptrnd)
+ return 0;
+
+ {
+ mp_digit top = DIGITS(mp)[ptrnd - 1];
+ lim >>= ((ptrnd - 1) * MP_DIGIT_BIT);
+ return top <= lim;
+ }
+}
+
+int mp_in_double_intptr_range(mp_int *mp)
+{
+ return s_mp_in_big_range(mp, DOUBLE_INTPTR_MAX, 0);
+}
+
+int mp_in_double_uintptr_range(mp_int *mp)
+{
+ return s_mp_in_big_range(mp, DOUBLE_UINTPTR_MAX, 1);
+}
+
#endif
mp_err mp_set_word(mp_int *mp, mp_word w, int sign)
diff --git a/mpi/mpi.h b/mpi/mpi.h
index 71e08055..cce283b0 100644
--- a/mpi/mpi.h
+++ b/mpi/mpi.h
@@ -90,6 +90,11 @@ int mp_in_intptr_range(mp_int *mp);
int mp_in_uintptr_range(mp_int *mp);
#ifdef HAVE_DOUBLE_INTPTR_T
mp_err mp_set_double_intptr(mp_int *mp, double_intptr_t z);
+mp_err mp_set_double_uintptr(mp_int *mp, double_uintptr_t z);
+mp_err mp_get_double_intptr(mp_int *mp, double_intptr_t *z);
+mp_err mp_get_double_uintptr(mp_int *mp, double_uintptr_t *z);
+int mp_in_double_intptr_range(mp_int *mp);
+int mp_in_double_uintptr_range(mp_int *mp);
#endif
mp_err mp_set_word(mp_int *mp, mp_word w, int sign);