1
|
1
|
;;; -*- Mode: Lisp; Package: Kernel -*-
|
2
|
2
|
;;;
|
3
|
3
|
;;; **********************************************************************
|
|
4
|
+;;; This code was written as part of CMU Common Lisp and has been
|
|
5
|
+;;; placed in the public domain, and is provided 'as is'.
|
|
6
|
+;;;
|
4
|
7
|
(ext:file-comment
|
5
|
8
|
"$Header: src/code/rand-xoroshiro.lisp $")
|
6
|
9
|
|
... |
... |
@@ -23,6 +26,12 @@ |
23
|
26
|
|
24
|
27
|
(sys:register-lisp-feature :random-xoroshiro)
|
25
|
28
|
|
|
29
|
+
|
|
30
|
+;;;; Random state hackery:
|
|
31
|
+
|
|
32
|
+;; Generate a random seed that can be used for seeding the generator.
|
|
33
|
+;; If /dev/urandom is available, it is used to generate random data as
|
|
34
|
+;; the seed. Otherwise, the current time is used as the seed.
|
26
|
35
|
(defun generate-seed (&optional (nwords 1))
|
27
|
36
|
;; On some systems (as reported by Ole Rohne on cmucl-imp),
|
28
|
37
|
;; /dev/urandom isn't what we think it is, so if it doesn't work,
|
... |
... |
@@ -51,7 +60,7 @@ |
51
|
60
|
(flet ((splitmix64 ()
|
52
|
61
|
;; See http://xoroshiro.di.unimi.it/splitmix64.c for the
|
53
|
62
|
;; definitive reference. The basic algorithm, where x is
|
54
|
|
- ;; the 64-bit state of the generator,:
|
|
63
|
+ ;; the 64-bit state of the generator, is:
|
55
|
64
|
;;
|
56
|
65
|
;; uint64_t z = (x += 0x9e3779b97f4a7c15);
|
57
|
66
|
;; z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
... |
... |
@@ -85,10 +94,14 @@ |
85
|
94
|
(aref state 1) (make-double s1))
|
86
|
95
|
state))))
|
87
|
96
|
|
|
97
|
+;; Initialize from an array. The KEY is a 2-element array of unsigned
|
|
98
|
+;; 64-bit integers. The state is set to the given 64-bit integer
|
|
99
|
+;; values.
|
88
|
100
|
(defun vec-init-xoro-state (key &optional (state (make-array 2 :element-type 'double-float)))
|
89
|
101
|
(declare (type (array (unsigned-byte 64) (2)) key)
|
90
|
102
|
(type (simple-array double-float (2)) state))
|
91
|
103
|
(flet ((make-double (x)
|
|
104
|
+ (declare (type (unsigned-byte 64) x))
|
92
|
105
|
(let ((hi (ldb (byte 32 32) x))
|
93
|
106
|
(lo (ldb (byte 32 0) x)))
|
94
|
107
|
(kernel:make-double-float
|
... |
... |
@@ -99,11 +112,11 @@ |
99
|
112
|
(setf (aref state 0) (make-double (aref key 0))
|
100
|
113
|
(aref state 1) (make-double (aref key 1)))
|
101
|
114
|
state))
|
102
|
|
-
|
103
|
|
-
|
|
115
|
+
|
|
116
|
+;; The default seed is the digits of Euler's constant, 0.5772....
|
104
|
117
|
(defun init-random-state (&optional (seed 5772156649015328606) state)
|
105
|
|
- "Generate an random state vector from the given SEED. The seed can be
|
106
|
|
- either an integer or a vector of (unsigned-byte 32)"
|
|
118
|
+ _N"Generate an random state vector from the given SEED. The seed can be
|
|
119
|
+ either an integer or a vector of (unsigned-byte 64)"
|
107
|
120
|
(declare (type (or null integer
|
108
|
121
|
(array (unsigned-byte 64) (*)))
|
109
|
122
|
seed))
|
... |
... |
@@ -180,6 +193,10 @@ |
180
|
193
|
(make-random-object))
|
181
|
194
|
|
182
|
195
|
(defun make-random-state (&optional state)
|
|
196
|
+ _N"Make a random state object. If STATE is not supplied, return a copy
|
|
197
|
+ of the default random state. If STATE is a random state, then return a
|
|
198
|
+ copy of it. If STATE is T then return a random state generated from
|
|
199
|
+ the universal time or /dev/urandom if available."
|
183
|
200
|
(flet ((copy-random-state (state)
|
184
|
201
|
(let ((old-state (random-state-state state))
|
185
|
202
|
(new-state
|
... |
... |
@@ -198,7 +215,7 @@ |
198
|
215
|
:rand 0
|
199
|
216
|
:cached-p nil))
|
200
|
217
|
(t
|
201
|
|
- (error "Argument is not a RANDOM-STATE, T, or NIL: ~S" state)))))
|
|
218
|
+ (error _"Argument is not a RANDOM-STATE, T, or NIL: ~S" state)))))
|
202
|
219
|
|
203
|
220
|
(defun rand-initializer ()
|
204
|
221
|
(init-random-state (generate-seed)
|
... |
... |
@@ -384,7 +401,7 @@ |
384
|
401
|
(double-float 0d0))
|
385
|
402
|
%random-double-float))
|
386
|
403
|
;;;
|
387
|
|
-;;; 53bit version.
|
|
404
|
+;;; 53-bit version.
|
388
|
405
|
;;;
|
389
|
406
|
(defun %random-double-float (arg state)
|
390
|
407
|
(declare (type (double-float (0d0)) arg)
|
... |
... |
@@ -452,10 +469,9 @@ |
452
|
469
|
(declare (fixnum count)))))
|
453
|
470
|
|
454
|
471
|
(defun random (arg &optional (state *random-state*))
|
455
|
|
- "Generate a uniformly distributed pseudo-random number between zero
|
|
472
|
+ _N"Generate a uniformly distributed pseudo-random number between zero
|
456
|
473
|
and Arg. State, if supplied, is the random state to use."
|
457
|
|
- (declare (inline %random-single-float %random-double-float
|
458
|
|
- #+long-float %long-float))
|
|
474
|
+ (declare (inline %random-single-float %random-double-float))
|
459
|
475
|
(cond
|
460
|
476
|
((typep arg '(integer 1 #x100000000))
|
461
|
477
|
;; Let the compiler deftransform take care of this case.
|
... |
... |
@@ -464,9 +480,6 @@ |
464
|
480
|
(%random-single-float arg state))
|
465
|
481
|
((and (typep arg 'double-float) (> arg 0.0D0))
|
466
|
482
|
(%random-double-float arg state))
|
467
|
|
- #+long-float
|
468
|
|
- ((and (typep arg 'long-float) (> arg 0.0L0))
|
469
|
|
- (%random-long-float arg state))
|
470
|
483
|
#+double-double
|
471
|
484
|
((and (typep arg 'double-double-float) (> arg 0.0w0))
|
472
|
485
|
(%random-double-double-float arg state))
|
... |
... |
@@ -475,13 +488,13 @@ |
475
|
488
|
(t
|
476
|
489
|
(error 'simple-type-error
|
477
|
490
|
:expected-type '(or (integer 1) (float (0.0))) :datum arg
|
478
|
|
- :format-control (intl:gettext "Argument is not a positive integer or a positive float: ~S")
|
|
491
|
+ :format-control _"Argument is not a positive integer or a positive float: ~S")
|
479
|
492
|
:format-arguments (list arg)))))
|
480
|
493
|
|
481
|
494
|
;; Jump function for the generator. See the jump function in
|
482
|
495
|
;; http://xoroshiro.di.unimi.it/xoroshiro128plus.c
|
483
|
496
|
(defun random-state-jump (&optional (rng-state *random-state*))
|
484
|
|
- "Jump the RNG-STATE. This is equivalent to 2^64 calls to the
|
|
497
|
+ _N"Jump the RNG-STATE. This is equivalent to 2^64 calls to the
|
485
|
498
|
xoroshiro128+ generator. It can be used to generate 2^64
|
486
|
499
|
non-overlapping subsequences for parallel computations."
|
487
|
500
|
(declare (type random-state rng-state))
|