| ... |
... |
@@ -8,7 +8,8 @@ |
|
8
|
8
|
;;; **********************************************************************
|
|
9
|
9
|
;;;
|
|
10
|
10
|
;;; Support for the xoroshiro128+ random number generator by David
|
|
11
|
|
-;;; Blackman and Sebastiano Vigna (vigna@acm.org)
|
|
|
11
|
+;;; Blackman and Sebastiano Vigna (vigna@acm.org). See
|
|
|
12
|
+;;; http://xoroshiro.di.unimi.it/.
|
|
12
|
13
|
|
|
13
|
14
|
(in-package "LISP")
|
|
14
|
15
|
(intl:textdomain "cmucl")
|
| ... |
... |
@@ -47,6 +48,18 @@ |
|
47
|
48
|
(let ((state (or state (make-array 2 :element-type 'double-float)))
|
|
48
|
49
|
(splitmix-state (ldb (byte 64 0) seed)))
|
|
49
|
50
|
(flet ((splitmix64 ()
|
|
|
51
|
+ ;; See http://xoroshiro.di.unimi.it/splitmix64.c for the
|
|
|
52
|
+ ;; definitive reference. The basic algorithm, where x is
|
|
|
53
|
+ ;; the 64-bit state of the generator,:
|
|
|
54
|
+ ;;
|
|
|
55
|
+ ;; uint64_t z = (x += 0x9e3779b97f4a7c15);
|
|
|
56
|
+ ;; z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
|
|
57
|
+ ;; z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
|
|
58
|
+ ;; return z ^ (z >> 31);
|
|
|
59
|
+ ;;
|
|
|
60
|
+ ;; This is only used occasionally for initializing the
|
|
|
61
|
+ ;; RNG, so this is a very straight-forward
|
|
|
62
|
+ ;; implementation.
|
|
50
|
63
|
(let ((z (setf splitmix-state
|
|
51
|
64
|
(ldb (byte 64 0) (+ splitmix-state #x9e3779b97f4a7c15)))))
|
|
52
|
65
|
(declare (type (unsigned-byte 64) z))
|
| ... |
... |
@@ -192,8 +205,8 @@ |
|
192
|
205
|
|
|
193
|
206
|
;;;; Random entries:
|
|
194
|
207
|
|
|
195
|
|
-;;#+x86
|
|
196
|
|
-;;(declaim (inline xoroshiro-next))
|
|
|
208
|
+#+x86
|
|
|
209
|
+(declaim (inline xoroshiro-gen))
|
|
197
|
210
|
#+x86
|
|
198
|
211
|
(defun xoroshiro-gen (state)
|
|
199
|
212
|
(declare (type (simple-array double-float (2)) state)
|
| ... |
... |
@@ -204,7 +217,31 @@ |
|
204
|
217
|
(defun xoroshiro-gen (state)
|
|
205
|
218
|
(declare (type (simple-array double-float (2)) state)
|
|
206
|
219
|
(optimize (speed 3) (safety 0)))
|
|
|
220
|
+ ;; Portable implemenation of the xoroshiro128+ generator. See
|
|
|
221
|
+ ;; http://xoroshiro.di.unimi.it/xoroshiro128plus.c for the
|
|
|
222
|
+ ;; definitive definition.
|
|
|
223
|
+ ;;
|
|
|
224
|
+ ;; uint64_t s[2];
|
|
|
225
|
+ ;;
|
|
|
226
|
+ ;; static inline uint64_t rotl(const uint64_t x, int k) {
|
|
|
227
|
+ ;; return (x << k) | (x >> (64 - k));
|
|
|
228
|
+ ;; }
|
|
|
229
|
+ ;;
|
|
|
230
|
+ ;; uint64_t next(void) {
|
|
|
231
|
+ ;; const uint64_t s0 = s[0];
|
|
|
232
|
+ ;; uint64_t s1 = s[1];
|
|
|
233
|
+ ;; const uint64_t result = s0 + s1;
|
|
|
234
|
+ ;;
|
|
|
235
|
+ ;; s1 ^= s0;
|
|
|
236
|
+ ;; s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b
|
|
|
237
|
+ ;; s[1] = rotl(s1, 36); // c
|
|
|
238
|
+ ;;
|
|
|
239
|
+ ;; return result;
|
|
|
240
|
+ ;; }
|
|
|
241
|
+ ;;
|
|
207
|
242
|
(flet ((rotl-55 (x1 x0)
|
|
|
243
|
+ ;; Rotate [x1|x0] left 55 bits, returning the result as two
|
|
|
244
|
+ ;; values.
|
|
208
|
245
|
(declare (type (unsigned-byte 32) x0 x1)
|
|
209
|
246
|
(optimize (speed 3) (safety 0)))
|
|
210
|
247
|
;; x << 55
|
| ... |
... |
@@ -218,6 +255,8 @@ |
|
218
|
255
|
(values (logior sl55-h sr9-h)
|
|
219
|
256
|
(logior sl55-l sr9-l)))))
|
|
220
|
257
|
(rotl-36 (x1 x0)
|
|
|
258
|
+ ;; Rotate [x1|x0] left 36 bits, returning the result as two
|
|
|
259
|
+ ;; values.
|
|
221
|
260
|
(declare (type (unsigned-byte 32) x0 x1)
|
|
222
|
261
|
(optimize (speed 3) (safety 0)))
|
|
223
|
262
|
;; x << 36
|
| ... |
... |
@@ -230,6 +269,8 @@ |
|
230
|
269
|
(values (logior sl36-h sr28-h)
|
|
231
|
270
|
sr28-l))))
|
|
232
|
271
|
(shl-14 (x1 x0)
|
|
|
272
|
+ ;; Shift [x1|x0] left by 14 bits, returning the result as
|
|
|
273
|
+ ;; two values.
|
|
233
|
274
|
(declare (type (unsigned-byte 32) x1 x0)
|
|
234
|
275
|
(optimize (speed 3) (safety 0)))
|
|
235
|
276
|
(values (ldb (byte 32 0)
|
| ... |
... |
@@ -248,6 +289,9 @@ |
|
248
|
289
|
(s1-1 0)
|
|
249
|
290
|
(s1-0 0))
|
|
250
|
291
|
(declare (type (unsigned-byte 32) s0-1 s0-0 s1-1 s1-0))
|
|
|
292
|
+ ;; Load the state to s0 and s1. s0-1 is the high 32-bit part and
|
|
|
293
|
+ ;; s0-0 is the low 32-bit part of the 64-bit value. Similarly
|
|
|
294
|
+ ;; for s1.
|
|
251
|
295
|
(multiple-value-bind (x1 x0)
|
|
252
|
296
|
(kernel:double-float-bits (aref state 0))
|
|
253
|
297
|
(setf s0-1 (ldb (byte 32 0) x1)
|
| ... |
... |
@@ -257,6 +301,7 @@ |
|
257
|
301
|
(setf s1-1 (ldb (byte 32 0) x1)
|
|
258
|
302
|
s1-0 x0))
|
|
259
|
303
|
|
|
|
304
|
+ ;; Compute the 64-bit random value: s0 + s1
|
|
260
|
305
|
(multiple-value-prog1
|
|
261
|
306
|
(multiple-value-bind (sum-0 c)
|
|
262
|
307
|
(bignum::%add-with-carry s0-0 s1-0 0)
|