~ chicken-core (chicken-5) 6a3a8253525816e876ca48398cbb2b3e8cf3dd11
commit 6a3a8253525816e876ca48398cbb2b3e8cf3dd11
Author: Kooda <kooda@upyum.com>
AuthorDate: Sat Nov 4 13:10:21 2017 +0100
Commit: Kooda <kooda@upyum.com>
CommitDate: Sat Nov 4 13:12:20 2017 +0100
Add pseudo-random-real to the chicken.random module.
Based on Taylor R. Campbell algorithm explained on
https://mumble.net/~campbell/2014/04/28/uniform-random-float
diff --git a/chicken.h b/chicken.h
index 357928b9..b0a7de30 100644
--- a/chicken.h
+++ b/chicken.h
@@ -2095,6 +2095,7 @@ C_fctexport void *C_lookup_procedure_ptr(C_char *id);
C_fctexport C_word C_random_fixnum(C_word n) C_regparm;
C_fctexport C_word C_fcall C_s_a_u_i_random_int(C_word **ptr, C_word n, C_word rn) C_regparm;
+C_fctexport C_word C_fcall C_a_i_random_real(C_word **ptr, C_word n) C_regparm;
C_fctexport C_word C_random_bytes(C_word buf, C_word size);
C_fctexport C_word C_set_random_seed(C_word buf, C_word n);
diff --git a/extras.scm b/extras.scm
index 10e1bf0c..0eaacd32 100644
--- a/extras.scm
+++ b/extras.scm
@@ -644,7 +644,7 @@
;;; Random numbers:
(module chicken.random
- (set-pseudo-random-seed! pseudo-random-integer random-bytes)
+ (set-pseudo-random-seed! pseudo-random-integer pseudo-random-real random-bytes)
(import scheme chicken chicken.time chicken.io foreign)
@@ -668,6 +668,9 @@
(else
(##core#inline_allocate ("C_s_a_u_i_random_int" 2) n))))
+(define (pseudo-random-real)
+ (##core#inline_allocate ("C_a_i_random_real" 2)))
+
(define random-bytes
(let ((nstate (foreign-value "C_RANDOM_STATE_SIZE" unsigned-int)))
(lambda (#!optional buf size)
diff --git a/runtime.c b/runtime.c
index 9d312478..5dc17466 100644
--- a/runtime.c
+++ b/runtime.c
@@ -12676,6 +12676,38 @@ C_s_a_u_i_random_int(C_word **ptr, C_word n, C_word rn)
return C_bignum_simplify(result);
}
+/*
+ * C_a_i_random_real: Generate a stream of bits uniformly at random and
+ * interpret it as the fractional part of the binary expansion of a
+ * number in [0, 1], 0.00001010011111010100...; then round it.
+ * More information on https://mumble.net/~campbell/2014/04/28/uniform-random-float
+ */
+#define random64() ((((C_u64) random_word()) << 32) | ((C_u64) random_word()))
+#define clz64 __builtin_clzll /* XXX GCCism */
+C_regparm C_word C_fcall
+C_a_i_random_real(C_word **ptr, C_word n) {
+ int exponent = -64;
+ uint64_t significand;
+ unsigned shift;
+
+ while (C_unlikely((significand = random64()) == 0)) {
+ exponent -= 64;
+ if (C_unlikely(exponent < -1074))
+ return 0;
+ }
+
+ shift = clz64(significand);
+ if (shift != 0) {
+ exponent -= shift;
+ significand <<= shift;
+ significand |= (random64() >> (64 - shift));
+ }
+
+ significand |= 1;
+ return C_flonum(ptr, ldexp((double)significand, exponent));
+}
+#undef random64
+
C_word C_set_random_seed(C_word buf, C_word n)
{
Trap