1 ;;;; This implementation of RANDOM is based on the Mersenne Twister random
2 ;;;; number generator "MT19937" due to Matsumoto and Nishimura. See:
3 ;;;; Makoto Matsumoto and T. Nishimura, "Mersenne twister: A
4 ;;;; 623-dimensionally equidistributed uniform pseudorandom number
5 ;;;; generator.", ACM Transactions on Modeling and Computer Simulation,
8 ;;;; This software is part of the SBCL system. See the README file for
11 ;;;; This software is derived from the CMU CL system, which was
12 ;;;; written at Carnegie Mellon University and released into the
13 ;;;; public domain. The software is in the public domain and is
14 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
15 ;;;; files for more information.
17 (in-package "SB!KERNEL")
21 (def!method make-load-form
((random-state random-state
) &optional environment
)
22 (make-load-form-saving-slots random-state
:environment environment
))
24 (def!method print-object
((state random-state
) stream
)
25 (if (and *print-readably
* (not *read-eval
*))
26 (error 'print-not-readable
:object state
)
27 (format stream
"#S(~S ~S #.~S)"
34 ',(coerce (random-state-state state
) 'list
)))))
36 ;;; The state is stored in a (simple-array (unsigned-byte 32) (627))
37 ;;; wrapped in a random-state structure:
39 ;;; 0-1: Constant matrix A. [0, #x9908b0df]
43 ;;; Generate and initialize a new random-state array. Index is
44 ;;; initialized to 1 and the states to 32bit integers excluding zero.
46 ;;; Seed - A 32bit number, not zero.
48 ;;; Apparently uses the generator Line 25 of Table 1 in
49 ;;; [KNUTH 1981, The Art of Computer Programming, Vol. 2 (2nd Ed.), pp102]
50 (defun init-random-state (&optional
(seed 4357) state
)
51 (declare (type (integer 1 #xffffffff
) seed
))
52 (let ((state (or state
(make-array 627 :element-type
'(unsigned-byte 32)))))
53 (declare (type (simple-array (unsigned-byte 32) (627)) state
))
54 (setf (aref state
1) #x9908b0df
)
55 (setf (aref state
2) 1)
56 (setf (aref state
3) seed
)
59 (declare (type (mod 625) k
))
60 (setf (aref state
(+ 3 k
))
61 (logand (* 69069 (aref state
(+ 3 (1- k
)))) #xffffffff
)))
64 (defvar *random-state
*)
65 (defun !random-cold-init
()
66 (/show0
"entering !RANDOM-COLD-INIT")
67 (setf *random-state
* (%make-random-state
))
68 (/show0
"returning from !RANDOM-COLD-INIT"))
70 (defun make-random-state (&optional state
)
72 "Make a random state object. If STATE is not supplied, return a copy
73 of the default random state. If STATE is a random state, then return a
74 copy of it. If STATE is T then return a random state generated from
76 (/show0
"entering MAKE-RANDOM-STATE")
77 (flet ((copy-random-state (state)
78 (/show0
"entering COPY-RANDOM-STATE")
79 (let ((state (random-state-state state
))
81 (make-array 627 :element-type
'(unsigned-byte 32))))
82 (/show0
"made NEW-STATE, about to DOTIMES")
84 (setf (aref new-state i
) (aref state i
)))
85 (/show0
"falling through to %MAKE-RANDOM-STATE")
86 (%make-random-state
:state new-state
))))
87 (/show0
"at head of ETYPECASE in MAKE-RANDOM-STATE")
91 (copy-random-state *random-state
*))
93 (/show0
"RANDOM-STATE-P clause")
94 (copy-random-state state
))
97 (%make-random-state
:state
(init-random-state
98 (logand (get-universal-time)
103 ;;; This function generates a 32bit integer between 0 and #xffffffff
105 #!-sb-fluid
(declaim (inline random-chunk
))
106 ;;; portable implementation
107 (defconstant mt19937-n
624)
108 (defconstant mt19937-m
397)
109 (defconstant mt19937-upper-mask
#x80000000
)
110 (defconstant mt19937-lower-mask
#x7fffffff
)
111 (defconstant mt19937-b
#x9D2C5680
)
112 (defconstant mt19937-c
#xEFC60000
)
114 (defun random-mt19937-update (state)
115 (declare (type (simple-array (unsigned-byte 32) (627)) state
)
116 (optimize (speed 3) (safety 0)))
118 (declare (type (unsigned-byte 32) y
))
120 ((>= kk
(+ 3 (- mt19937-n mt19937-m
))))
121 (declare (type (mod 628) kk
))
122 (setf y
(logior (logand (aref state kk
) mt19937-upper-mask
)
123 (logand (aref state
(1+ kk
)) mt19937-lower-mask
)))
124 (setf (aref state kk
) (logxor (aref state
(+ kk mt19937-m
))
125 (ash y -
1) (aref state
(logand y
1)))))
126 (do ((kk (+ (- mt19937-n mt19937-m
) 3) (1+ kk
)))
127 ((>= kk
(+ (1- mt19937-n
) 3)))
128 (declare (type (mod 628) kk
))
129 (setf y
(logior (logand (aref state kk
) mt19937-upper-mask
)
130 (logand (aref state
(1+ kk
)) mt19937-lower-mask
)))
131 (setf (aref state kk
) (logxor (aref state
(+ kk
(- mt19937-m mt19937-n
)))
132 (ash y -
1) (aref state
(logand y
1)))))
133 (setf y
(logior (logand (aref state
(+ 3 (1- mt19937-n
)))
135 (logand (aref state
3) mt19937-lower-mask
)))
136 (setf (aref state
(+ 3 (1- mt19937-n
)))
137 (logxor (aref state
(+ 3 (1- mt19937-m
)))
138 (ash y -
1) (aref state
(logand y
1)))))
141 (defun random-chunk (state)
142 (declare (type random-state state
))
143 (let* ((state (random-state-state state
))
145 (declare (type (mod 628) k
))
146 (when (= k mt19937-n
)
147 (random-mt19937-update state
)
149 (setf (aref state
2) (1+ k
))
150 (let ((y (aref state
(+ 3 k
))))
151 (declare (type (unsigned-byte 32) y
))
152 (setf y
(logxor y
(ash y -
11)))
153 (setf y
(logxor y
(ash (logand y
(ash mt19937-b -
7)) 7)))
154 (setf y
(logxor y
(ash (logand y
(ash mt19937-c -
15)) 15)))
155 (setf y
(logxor y
(ash y -
18)))
158 ;;; Using inline VOP support, only available on the x86 so far.
160 ;;; FIXME: It would be nice to have some benchmark numbers on this.
161 ;;; My inclination is to get rid of the nonportable implementation
162 ;;; unless the performance difference is just enormous.
164 (defun random-chunk (state)
165 (declare (type random-state state
))
166 (sb!vm
::random-mt19937
(random-state-state state
)))
168 #!-sb-fluid
(declaim (inline big-random-chunk
))
169 (defun big-random-chunk (state)
170 (declare (type random-state state
))
171 (logand (1- (expt 2 64))
172 (logior (ash (random-chunk state
) 32)
173 (random-chunk state
))))
175 ;;; Handle the single or double float case of RANDOM. We generate a
176 ;;; float between 0.0 and 1.0 by clobbering the significand of 1.0
177 ;;; with random bits, then subtracting 1.0. This hides the fact that
178 ;;; we have a hidden bit.
179 #!-sb-fluid
(declaim (inline %random-single-float %random-double-float
))
180 (declaim (ftype (function ((single-float (0f0)) random-state
)
182 %random-single-float
))
183 (defun %random-single-float
(arg state
)
184 (declare (type (single-float (0f0)) arg
)
185 (type random-state state
))
187 (- (make-single-float
188 (dpb (ash (random-chunk state
)
189 (- sb
!vm
:single-float-digits random-chunk-length
))
190 sb
!vm
:single-float-significand-byte
191 (single-float-bits 1.0)))
193 (declaim (ftype (function ((double-float (0d0)) random-state
)
195 %random-double-float
))
199 (defun %random-double-float
(arg state
)
200 (declare (type (double-float (0d0)) arg
)
201 (type random-state state
))
202 (* (float (random-chunk state
) 1d0
) (/ 1d0
(expt 2 32))))
206 (defun %random-double-float
(arg state
)
207 (declare (type (double-float (0d0)) arg
)
208 (type random-state state
))
210 (- (sb!impl
::make-double-float
211 (dpb (ash (random-chunk state
)
212 (- sb
!vm
:double-float-digits random-chunk-length
32))
213 sb
!vm
:double-float-significand-byte
214 (sb!impl
::double-float-high-bits
1d0
))
215 (random-chunk state
))
218 ;;; using a faster inline VOP
220 (defun %random-double-float
(arg state
)
221 (declare (type (double-float (0d0)) arg
)
222 (type random-state state
))
223 (let ((state-vector (random-state-state state
)))
225 (- (sb!impl
::make-double-float
226 (dpb (ash (sb!vm
::random-mt19937 state-vector
)
227 (- sb
!vm
:double-float-digits random-chunk-length
229 sb
!vm
:double-float-significand-byte
230 (sb!impl
::double-float-high-bits
1d0
))
231 (sb!vm
::random-mt19937 state-vector
))
237 (defun %random-integer
(arg state
)
238 (declare (type (integer 1) arg
) (type random-state state
))
239 (let ((shift (- random-chunk-length random-integer-overlap
)))
240 (do ((bits (random-chunk state
)
241 (logxor (ash bits shift
) (random-chunk state
)))
242 (count (+ (integer-length arg
)
243 (- random-integer-extra-bits shift
))
247 (declare (fixnum count
)))))
249 (defun random (arg &optional
(state *random-state
*))
250 (declare (inline %random-single-float %random-double-float
251 #!+long-float %random-long-float
))
253 ((and (fixnump arg
) (<= arg random-fixnum-max
) (> arg
0))
254 (rem (random-chunk state
) arg
))
255 ((and (typep arg
'single-float
) (> arg
0.0f0
))
256 (%random-single-float arg state
))
257 ((and (typep arg
'double-float
) (> arg
0.0d0
))
258 (%random-double-float arg state
))
260 ((and (typep arg
'long-float
) (> arg
0.0l0))
261 (%random-long-float arg state
))
262 ((and (integerp arg
) (> arg
0))
263 (%random-integer arg state
))
265 (error 'simple-type-error
266 :expected-type
'(or (integer 1) (float (0))) :datum arg
267 :format-control
"~@<Argument is neither a positive integer nor a ~
268 positive float: ~2I~_~S~:>"
269 :format-arguments
(list arg
)))))