summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-10-25 07:29:11 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-10-25 07:29:11 -0700
commit76b97f2c904c4e52d11e89406a9491aef77ef438 (patch)
tree06e454db8c86cf2e376e61e6f75c59ad21f3e673
parent23ff8e0205eabea96a109efd249f82dd562cf74e (diff)
downloadtxr-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.c37
-rw-r--r--stdlib/doc-syms.tl3
-rw-r--r--txr.132
3 files changed, 70 insertions, 2 deletions
diff --git a/rand.c b/rand.c
index 7e3bd735..6202a74c 100644
--- a/rand.c
+++ b/rand.c
@@ -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")
diff --git a/txr.1 b/txr.1
index 052dc739..5df87f49 100644
--- a/txr.1
+++ b/txr.1
@@ -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 ])