From 62ec2d2ec9d427866c9dea6fc507ea1c7976fb0f Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 14 Mar 2014 00:26:37 -0700 Subject: * eval.c (eval_init): Make seed argument optional in make-random-state. * rand.c (make_random_state): Do argument defaulting on seed. Also, mix getpid() into the seed. (random_fixnum): Bugfix: do proper defaulting on optional agument, rather than relying on nil. (random): Fix 2014-02-05 regression. This was totally broken, ignoring the random state passed in and using the global random state. This function must only use the state passed in; there is no defaulting to the global random state. * txr.1: Documenting that seed is optional in make-random-state. Describing what guarantees can be expected with regard to calls made close together temporally. --- ChangeLog | 17 +++++++++++++++++ eval.c | 2 +- rand.c | 15 ++++++++++----- txr.1 | 27 ++++++++++++++++++++++++--- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4593c47d..e9dc9c2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2014-03-14 Kaz Kylheku + + * eval.c (eval_init): Make seed argument optional in make-random-state. + + * rand.c (make_random_state): Do argument defaulting on seed. + Also, mix getpid() into the seed. + (random_fixnum): Bugfix: do proper defaulting on optional + agument, rather than relying on nil. + (random): Fix 2014-02-05 regression. This was totally broken, + ignoring the random state passed in and using the global + random state. This function must only use the state passed in; + there is no defaulting to the global random state. + + * txr.1: Documenting that seed is optional in make-random-state. + Describing what guarantees can be expected with regard to + calls made close together temporally. + 2014-03-13 Kaz Kylheku Implementing @(if)/@(elif)/@(else) in the pattern language. diff --git a/eval.c b/eval.c index 8cf1f75c..a0f73610 100644 --- a/eval.c +++ b/eval.c @@ -3510,7 +3510,7 @@ void eval_init(void) reg_fun(intern(lit("functionp"), user_package), func_n1(functionp)); reg_fun(intern(lit("interp-fun-p"), user_package), func_n1(interp_fun_p)); - reg_fun(intern(lit("make-random-state"), user_package), func_n1(make_random_state)); + reg_fun(intern(lit("make-random-state"), user_package), func_n1o(make_random_state, 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, 1)); reg_fun(intern(lit("random"), user_package), func_n2(random)); diff --git a/rand.c b/rand.c index d9f939e3..a934667e 100644 --- a/rand.c +++ b/rand.c @@ -37,6 +37,9 @@ #include #include #include "config.h" +#if HAVE_UNISTD_H +#include +#endif #include "lib.h" #include "signal.h" #include "unwind.h" @@ -110,6 +113,8 @@ val make_random_state(val seed) r->cur = 0; + seed = default_bool_arg(seed); + if (bignump(seed)) { int i, dig, bit; mp_int *m = mp(seed); @@ -139,7 +144,8 @@ val make_random_state(val seed) val time = time_sec_usec(); r->state[0] = (rand32_t) c_num(car(time)); r->state[1] = (rand32_t) c_num(cdr(time)); - memset(r->state + 2, 0xAA, sizeof r->state - 2 * sizeof r->state[0]); + r->state[2] = (rand32_t) getpid(); + memset(r->state + 3, 0xAA, sizeof r->state - 3 * sizeof r->state[0]); } else if (random_state_p(seed)) { struct rand_state *rseed = (struct rand_state *) cobj_handle(seed, random_state_s); @@ -157,16 +163,15 @@ val make_random_state(val seed) val random_fixnum(val state) { - uses_or2; - struct rand_state *r = (struct rand_state *) cobj_handle(or2(state, - random_state), + struct rand_state *r = (struct rand_state *) cobj_handle(default_arg(state, + random_state), random_state_s); return num(rand32(r) & NUM_MAX); } val random(val state, val modulus) { - struct rand_state *r = (struct rand_state *) cobj_handle(random_state, + struct rand_state *r = (struct rand_state *) cobj_handle(state, random_state_s); if (bignump(modulus)) { diff --git a/txr.1 b/txr.1 index 1f39a45c..86b30e8d 100644 --- a/txr.1 +++ b/txr.1 @@ -12546,7 +12546,7 @@ the call (make-random-state 42). .TP Syntax: - (make-random-state ) + (make-random-state []) .TP Description: @@ -12554,11 +12554,32 @@ Description: The make-random-state function creates and returns a new random state, an object of the same kind as what is stored in the *random-state* variable. -The seed must be an integer value. +The seed, if specified, must be an integer value. -Note that the sign of the value is ignored, so that negative seed +Note that the sign of the seed is ignored, so that negative seed values are equivalent to their additive inverses. +If the seed is not specified, then make-random-state produces a seed based +on some information in the process environment, such as current +time of day. It is not guaranteed that two calls to (make-random-state nil) +that are separated by less than some minimum increment of real time produce +different seeds. The minimum time increment depends on the platform, but on any +given platform, it is the platform's smallest available time increment, or a +microsecond, whichever is longer. + +Of course, it is not guranteed that any two calls to make-random-state produce +different values under any circumstances, due to possible collisions; however, +time differences smaller than the minimum increment may predictably produce +identical values. + +For instance, on a platform with a nanosecond-resolution real-time clock, +the minimum time increment is a microsecond. Calls to make-random-state +closer together than a microsecond may predictably produce the same seed. + +In a platform with a millisecond-resolution real-time clock, the minimum +time increment is a millisecond. Calls to make-random-state less than +a millisecond apart may predictably produce the same seed. + .SS Function random-state-p .TP -- cgit v1.2.3