summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arith.c40
-rw-r--r--arith.h2
-rw-r--r--eval.c2
-rw-r--r--mpi/mpi.c38
-rw-r--r--mpi/mpi.h2
-rw-r--r--rand.c28
-rw-r--r--rand.h1
-rw-r--r--txr.129
8 files changed, 127 insertions, 15 deletions
diff --git a/arith.c b/arith.c
index 280d3b55..497aefa7 100644
--- a/arith.c
+++ b/arith.c
@@ -48,7 +48,7 @@
#define CNUM_BIT ((int) sizeof (cnum) * CHAR_BIT)
#define ABS(A) ((A) < 0 ? -(A) : (A))
-static mp_int NUM_MAX_MP, INT_PTR_MAX_MP;
+static mp_int NUM_MAX_MP, INT_PTR_MAX_MP, UINT_PTR_MAX_MP;
val make_bignum(void)
{
@@ -83,6 +83,13 @@ val bignum_from_long(long l)
#endif
}
+val bignum_from_uintptr(uint_ptr_t u)
+{
+ val n = make_bignum();
+ mp_set_uintptr(mp(n), u);
+ return n;
+}
+
#if HAVE_DOUBLE_INTPTR_T
static val bignum_dbl_ipt(double_intptr_t di)
@@ -110,6 +117,35 @@ val in_int_ptr_range(val bignum)
return (mp_cmp_mag(mp(bignum), &INT_PTR_MAX_MP) == MP_GT) ? nil : t;
}
+static val in_uint_ptr_range(val bignum)
+{
+ return (mp_cmp_z(mp(bignum)) == MP_LT ||
+ mp_cmp_mag(mp(bignum), &UINT_PTR_MAX_MP) == MP_GT) ? nil : t;
+}
+
+uint_ptr_t c_uint_ptr_num(val num)
+{
+ switch (type(num)) {
+ case CHR: case NUM:
+ {
+ cnum n = coerce(cnum, num) >> TAG_SHIFT;
+ if (n >= 0)
+ return n;
+ }
+ goto range;
+ case BGNUM:
+ if (in_uint_ptr_range(num)) {
+ uint_ptr_t out;
+ mp_get_uintptr(mp(num), &out);
+ return out;
+ }
+ range:
+ uw_throwf(error_s, lit("~s is out of uint_ptr_t range"), num, nao);
+ default:
+ type_mismatch(lit("~s is not an integer"), num, nao);
+ }
+}
+
int highest_bit(int_ptr_t n)
{
#if SIZEOF_PTR == 8
@@ -2275,6 +2311,8 @@ void arith_init(void)
mp_set_intptr(&NUM_MAX_MP, NUM_MAX);
mp_init(&INT_PTR_MAX_MP);
mp_set_intptr(&INT_PTR_MAX_MP, INT_PTR_MAX);
+ mp_init(&UINT_PTR_MAX_MP);
+ mp_set_uintptr(&UINT_PTR_MAX_MP, -1);
log2_init();
reg_varl(intern(lit("*flo-dig*"), user_package), num_fast(DBL_DIG));
diff --git a/arith.h b/arith.h
index 62284e7e..083a8a19 100644
--- a/arith.h
+++ b/arith.h
@@ -27,9 +27,11 @@
val make_bignum(void);
val bignum(cnum cn);
val bignum_from_long(long l);
+val bignum_from_uintptr(uint_ptr_t u);
int highest_bit(int_ptr_t n);
val normalize(val bignum);
val in_int_ptr_range(val bignum);
+uint_ptr_t c_uint_ptr_num(val num);
val cum_norm_dist(val x);
val n_choose_k(val n, val k);
val n_perm_k(val n, val k);
diff --git a/eval.c b/eval.c
index 654fe8ae..d202cd81 100644
--- a/eval.c
+++ b/eval.c
@@ -5156,6 +5156,8 @@ void eval_init(void)
reg_fun(intern(lit("interp-fun-p"), user_package), func_n1(interp_fun_p));
reg_fun(intern(lit("make-random-state"), user_package), func_n1o(make_random_state, 0));
+ reg_fun(intern(lit("random-state-get-vec"), user_package),
+ func_n1o(random_state_get_vec, 0));
reg_fun(intern(lit("random-state-p"), user_package), func_n1(random_state_p));
reg_fun(intern(lit("random-fixnum"), user_package), func_n1o(random_fixnum, 0));
reg_fun(intern(lit("random"), user_package), func_n2(random));
diff --git a/mpi/mpi.c b/mpi/mpi.c
index 20a48a12..0b5e622f 100644
--- a/mpi/mpi.c
+++ b/mpi/mpi.c
@@ -526,19 +526,17 @@ mp_err mp_set_int(mp_int *mp, long z)
/* }}} */
-mp_err mp_set_intptr(mp_int *mp, int_ptr_t z)
+mp_err mp_set_uintptr(mp_int *mp, uint_ptr_t z)
{
- int_ptr_t v = z > 0 ? z : -z;
-
if (sizeof z > sizeof (mp_digit)) {
int ix, shift;
- const int nd = (sizeof v + sizeof (mp_digit) - 1) / sizeof (mp_digit);
+ const int nd = (sizeof z + sizeof (mp_digit) - 1) / sizeof (mp_digit);
ARGCHK(mp != NULL, MP_BADARG);
mp_zero(mp);
- if(z == 0)
+ if (z == 0)
return MP_OKAY; /* shortcut for zero */
s_mp_grow(mp, nd);
@@ -547,24 +545,32 @@ mp_err mp_set_intptr(mp_int *mp, int_ptr_t z)
for (ix = 0, shift = 0; ix < nd; ix++, shift += MP_DIGIT_BIT)
{
- DIGIT(mp, ix) = (v >> shift) & MP_DIGIT_MAX;
+ DIGIT(mp, ix) = (z >> shift) & MP_DIGIT_MAX;
}
+
} else {
- mp_set(mp, v);
+ mp_set(mp, z);
}
+ return MP_OKAY;
+}
- if(z < 0)
+mp_err mp_set_intptr(mp_int *mp, int_ptr_t z)
+{
+ int_ptr_t v = z > 0 ? z : -z;
+ mp_err err = mp_set_uintptr(mp, v);
+
+ if (err == MP_OKAY && z < 0)
SIGN(mp) = MP_NEG;
- return MP_OKAY;
+ return err;
}
/*
* No checks here: assumes that the mp is in range!
*/
-mp_err mp_get_intptr(mp_int *mp, int_ptr_t *z)
+mp_err mp_get_uintptr(mp_int *mp, uint_ptr_t *z)
{
- int_ptr_t out = 0;
+ uint_ptr_t out = 0;
#if MP_DIGIT_SIZE < SIZEOF_PTR
int ix;
@@ -579,6 +585,16 @@ mp_err mp_get_intptr(mp_int *mp, int_ptr_t *z)
return MP_OKAY;
}
+mp_err mp_get_intptr(mp_int *mp, int_ptr_t *z)
+{
+ uint_ptr_t tmp = 0;
+ int_ptr_t out;
+ mp_get_uintptr(mp, &tmp);
+ out = tmp;
+ *z = (SIGN(mp) == MP_NEG) ? -out : out;
+ return MP_OKAY;
+}
+
#ifdef HAVE_DOUBLE_INTPTR_T
mp_err mp_set_double_intptr(mp_int *mp, double_intptr_t z)
{
diff --git a/mpi/mpi.h b/mpi/mpi.h
index fb9e47e8..ac2929d3 100644
--- a/mpi/mpi.h
+++ b/mpi/mpi.h
@@ -101,7 +101,9 @@ void mp_clear_array(mp_int mp[], int count);
void mp_zero(mp_int *mp);
void mp_set(mp_int *mp, mp_digit d);
mp_err mp_set_int(mp_int *mp, long z);
+mp_err mp_set_uintptr(mp_int *mp, uint_ptr_t z);
mp_err mp_set_intptr(mp_int *mp, int_ptr_t z);
+mp_err mp_get_uintptr(mp_int *mp, uint_ptr_t *z);
mp_err mp_get_intptr(mp_int *mp, int_ptr_t *z);
#ifdef HAVE_DOUBLE_INTPTR_T
mp_err mp_set_double_intptr(mp_int *mp, double_intptr_t z);
diff --git a/rand.c b/rand.c
index fe3b6044..e2d5c9d7 100644
--- a/rand.c
+++ b/rand.c
@@ -156,6 +156,18 @@ val make_random_state(val seed)
cobj_handle(seed, random_state_s));
*r = *rseed;
copy = 1;
+ } else if (vectorp(seed)) {
+ int i;
+
+ if (length(seed) < num_fast(17))
+ uw_throwf(error_s, lit("make-random-state: vector ~s too short"),
+ seed, nao);
+
+ for (i = 0; i < 16; i++)
+ r->state[i] = c_uint_ptr_num(seed->v.vec[i]);
+
+ r->cur = c_num(seed->v.vec[i]);
+ copy = 1;
} else {
uw_throwf(error_s, lit("make-random-state: seed ~s is not a number"),
seed, nao);
@@ -170,6 +182,22 @@ val make_random_state(val seed)
return rs;
}
+val random_state_get_vec(val state)
+{
+ struct rand_state *r = coerce(struct rand_state *,
+ cobj_handle(default_arg(state, random_state),
+ random_state_s));
+ int i;
+ val vec = vector(num_fast(17), nil);
+
+ for (i = 0; i < 16; i++)
+ vec->v.vec[i] = normalize(bignum_from_uintptr(r->state[i]));
+
+ vec->v.vec[i] = num(r->cur);
+
+ return vec;
+}
+
val random_fixnum(val state)
{
struct rand_state *r = coerce(struct rand_state *,
diff --git a/rand.h b/rand.h
index 0e85bc09..97dc4bc7 100644
--- a/rand.h
+++ b/rand.h
@@ -27,6 +27,7 @@
#define random_state (deref(lookup_var_l(nil, random_state_var_s)))
extern val random_state_s, random_state_var_s;
val make_random_state(val seed);
+val random_state_get_vec(val state);
val random_state_p(val obj);
val random_fixnum(val state);
val random(val state, val modulus);
diff --git a/txr.1 b/txr.1
index 9568e6b1..3062001f 100644
--- a/txr.1
+++ b/txr.1
@@ -34757,8 +34757,10 @@ an object of the same kind as what is stored in the
.code *random-state*
variable.
-The seed, if specified, must be either an integer value, or an
-existing random state object.
+The seed, if specified, must be either an integer value, an
+existing random state object, or a vector returned from a call
+to the function
+.codn random-state-get-vec .
Note that the sign of the seed is ignored, so that negative seed
values are equivalent to their additive inverses.
@@ -34779,11 +34781,17 @@ a millisecond apart may predictably produce the same seed.
If an integer seed is specified, then the integer value is mapped to a
pseudo-random sequence, in a platform-independent way.
-If a random state is specified as a seed, then it is duplicated. The
+If an existing random state is specified as a seed, then it is duplicated. The
returned random state object is a distinct object which is in the same
state as the input object. It will produce the same remaining pseudo-random
number sequence, as will the input object.
+If a vector is specified as a seed, then a random state is constructed
+which duplicates the random state object which was captured in that vector
+representation by the
+.code random-state-get-vec
+function.
+
.coNP Function @ random-state-p
.synb
.mets (random-state-p << obj )
@@ -34799,6 +34807,21 @@ is a random state, otherwise it
returns
.codn nil .
+.coNP Function @ random-state-get-vec
+.synb
+.mets (random-state-get-vec <> [ random-state ])
+.syne
+.desc
+The
+.code random-state-get-vec
+function converts a random state into a vector of integer values.
+If the
+.meta random-state
+argument, which must be a random state object, is omitted,
+then the value of the
+.code *random-state*
+is used.
+
.coNP Functions @, random-fixnum @ random and @ rand
.synb
.mets (random-fixnum <> [ random-state ])