diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-01-25 06:59:29 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-01-25 06:59:29 -0800 |
commit | 4b789435f8e4bb6ec9ea4bab3d0a109682adafa6 (patch) | |
tree | 65f91721ae512480ea4df6b9f7f493b35eab6660 /mpi | |
parent | 4c71a77f2c39a8158c80b40af1a5cc2358251a00 (diff) | |
download | txr-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.c | 82 | ||||
-rw-r--r-- | mpi/mpi.h | 5 |
2 files changed, 86 insertions, 1 deletions
@@ -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) @@ -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); |