diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2021-10-25 07:29:11 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2021-10-25 07:29:11 -0700 |
commit | 76b97f2c904c4e52d11e89406a9491aef77ef438 (patch) | |
tree | 06e454db8c86cf2e376e61e6f75c59ad21f3e673 | |
parent | 23ff8e0205eabea96a109efd249f82dd562cf74e (diff) | |
download | txr-76b97f2c904c4e52d11e89406a9491aef77ef438.tar.gz txr-76b97f2c904c4e52d11e89406a9491aef77ef438.tar.bz2 txr-76b97f2c904c4e52d11e89406a9491aef77ef438.zip |
random: new function random-float-incl.
This function includes the 1.0 value excluded by random-float.
* rand.c (random_float_incl): New static function.
(rand_init): Register random_float_incl intrinsic.
* txr.1: Document, and add discussion about uniformity requirements
and what they mean and do not mean.
* stdlib/doc-syms.tl: Updated.
-rw-r--r-- | rand.c | 37 | ||||
-rw-r--r-- | stdlib/doc-syms.tl | 3 | ||||
-rw-r--r-- | txr.1 | 32 |
3 files changed, 70 insertions, 2 deletions
@@ -312,6 +312,42 @@ static val random_float(val state) return flo(h.d - 1.0); } +static val random_float_incl(val state) +{ + val self = lit("random-float-incl"); + struct rand_state *r = coerce(struct rand_state *, + cobj_handle(self, + default_arg(state, random_state), + random_state_cls)); + union hack { + volatile double d; + struct { +#if HAVE_LITTLE_ENDIAN + volatile rand32_t lo, hi; +#else + volatile rand32_t hi, lo; +#endif + } r; + } h; + + h.r.lo = rand32(r); + + for (;;) { + rand32_t hi = rand32(r) & 0x1FFFFF; + rand32_t lo = rand32(r); + + if (hi == 0x100000 && lo == 0) + return flo(1.0); + + if ((hi & 0x100000) != 0) + continue; + + h.r.hi = (hi & 0xFFFFF) | (1023UL << 20); + + return flo(h.d - 1.0); + } +} + val random(val state, val modulus) { val self = lit("random"); @@ -475,6 +511,7 @@ void rand_init(void) 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-float"), user_package), func_n1o(random_float, 0)); + reg_fun(intern(lit("random-float-incl"), user_package), func_n1o(random_float_incl, 0)); reg_fun(intern(lit("random"), user_package), func_n2(random)); reg_fun(intern(lit("rand"), user_package), func_n2o(rnd, 1)); reg_fun(intern(lit("random-buf"), user_package), func_n2o(random_buf, 1)); diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl index 295471c2..38f5dc7b 100644 --- a/stdlib/doc-syms.tl +++ b/stdlib/doc-syms.tl @@ -1530,7 +1530,8 @@ ("random" "N-03A57C86") ("random-buf" "N-00161346") ("random-fixnum" "N-03A57C86") - ("random-float" "N-01572D27") + ("random-float" "N-0336F715") + ("random-float-inc" "N-0336F715") ("random-state-get-vec" "N-005C0F98") ("random-state-p" "N-00C9A749") ("range" "N-033BE5A1") @@ -63003,21 +63003,51 @@ argument must be a positive integer. If is 1, then the function returns zero without altering the state of the pseudorandom number generator. -.coNP Function @ random-float +.coNP Functions @ random-float and @ random-float-incl .synb .mets (random-float <> [ random-state ]) +.mets (random-float-incl <> [ random-state ])l .syne .desc The .code random-float function produces a pseudorandom floating-point value in the range [0.0, 1.0). +The +.code random-float-incl +produces a pseudorandom floating-point value in the range [0.0, 1.0], thus +differing from +.code random-float +by including the 1.0 limit value. + The numbers are obtained from a WELL512a PRNG, whose state is stored in the random state object given by the argument to the optional .meta random-state parameter, which defaults to the value of .codn *random-state* . +Because the floating-point type does not provide a representation of every real +value in the range 0.0 to 1.0, it is not possible to impose the requirement +that every value shall occur with equal likelihood. + +Rather, these functions are intended to produce an a uniform distribution of +values according to the following pragmatic requirements. A subset +.I S +of the real values in the +specified range, [0.0, 1.0) or [0.0, 1.0] is identified whose elements are representable +in the floating-point type and which are uniformly spaced along the interval. Then, +a random element is chosen from +.I S +and returned, such that every element is equally likely to be selected. + +Note that these requirements do not correspond to the more mathematically ideal +concept of uniformly choosing actual real numbers in the [0, 1] interval of the +real number line, and then finding the closest floating-point representation. +Such a requirement would mean that the boundary values 0.0 and 1.0 appear in +the output half as frequently as all the interior values, because each of these +two floating-point values is a representations of a range of numbers, half of +which lies outside of the [0, 1] interval. + .coNP Function @ random-buf .synb .mets (random-buf < size <> [ random-state ]) |