Diff of Modified rand-mt19937.lisp source code wrt to original. x86-dependent stuff and /dev/urandom have fallen by the wayside. Declarations modified to make Clisp and GCL happy.

--- rand-mt19937.lisp-orig      2005-01-07 21:24:05.000000000 -0700
+++ rand-mt19937.lisp   2005-01-14 09:55:22.000000000 -0700
@@ -1,10 +1,26 @@
-;;; -*- Mode: Lisp; Package: Kernel -*-
-;;;
-;;; **********************************************************************
-;;; This code was written by Douglas T. Crosher and Raymond Toy based
-;;; on public domain code from Carnegie Mellon University and has been
-;;; placed in the Public domain, and is provided 'as is'.
-;;;
-(ext:file-comment
-  "$Header: /project/cmucl/cvsroot/src/code/rand-mt19937.lisp,v 1.11 2003/03/06 09:31:06 emarsden Exp $")
-;;;
+;;; Mersenne Twister MT19937, adapted from CMUCL rand-mt19937.lisp -r1.11 (2003/03/06)
+
+;;; CMUCL version by Douglas T. Crosher and Raymond Toy based
+;;; on public domain code from Carnegie Mellon University.
+;;; Modified for Maxima by Robert Dodier.
+;;; (1) Construct floating point numbers using portable operations.
+;;; (2) Construct large integers using all bits of each chunk.
+
+(defpackage "MT19937"
+  (:use :common-lisp)
+  (:shadow #:random-state
+       #:random-state-p
+       #:random
+       #:*random-state*
+       #:make-random-state)
+  (:export #:random-state
+       #:random-state-p
+       #:random
+       #:*random-state*
+       #:make-random-state
+       #:%random-single-float
+       #:%random-double-float
+       #:random-chunk
+       #:init-random-state))
+
+;;; Begin MT19937 implementation.
@@ -22,6 +38 @@
-(in-package "LISP")
-(export '(random-state random-state-p random *random-state*
-         make-random-state))
-
-(in-package "KERNEL")
-(export '(%random-single-float %random-double-float random-chunk init-random-state))
+(in-package "MT19937")
@@ -29 +40,7 @@
-

+(defconstant mt19937-n 624)
+(defconstant mt19937-m 397)
+(defconstant mt19937-upper-mask #x80000000)
+(defconstant mt19937-lower-mask #x7fffffff)
+(defconstant mt19937-b #x9D2C5680)
+(defconstant mt19937-c #xEFC60000)
+;;;
@@ -42,21 +59,4 @@
-;; If /dev/urandom is available, it is used to generate random data as
-;; the seed.  Otherwise, the current time is used as the seed.
-;;
-;; The /dev/urandom device exists on Linux, FreeBSD, Solaris 8 and
-;; later. (You need to have patch 112438-01 for Solaris 8 to get that
-;; device, though). It returns pseudorandom data with entropy that the
-;; kernel collects from the environment. Unlike the related
-;; /dev/random, this device does not block when the entropy pool has
-;; been depleted.
-(defun generate-seed (&optional (nwords 1))
-  (cond ((probe-file "/dev/urandom")
-        (let ((words (make-array nwords :element-type '(unsigned-byte 32))))
-          (with-open-file (rand "/dev/urandom"
-                                :direction :input
-                                :element-type '(unsigned-byte 32))
-            (read-sequence words rand))
-          (if (= nwords 1)
-              (aref words 0)
-              words)))
-        (t
-         (logand (get-universal-time) #xffffffff))))
+;; The current time is used as the seed.
+
+(defun generate-seed ()
+         (logand (get-universal-time) #xffffffff))
@@ -186,2 +186 @@
-            (:constructor make-random-object)
-            (:make-load-form-fun :just-dump-it-normally))
+            (:constructor make-random-object))
@@ -195,2 +194,3 @@
-  copy of it.  If STATE is T then return a random state generated from
-  the universal time or /dev/urandom if available."
+  copy of STATE.  If STATE is T then return a random state generated from
+  the universal time.  To make a random state from an integer seed, try
+  ``(make-random-object :state (init-random-state <seed>))''."
@@ -210,7 +209,0 @@
-(defun rand-mt19937-initializer ()
-  (init-random-state (generate-seed)
-                     (random-state-state *random-state*)))
-
-(pushnew 'rand-mt19937-initializer ext:*after-save-initializations*)
-
-

@@ -231,8 +223,0 @@
-(defconstant mt19937-n 624)
-(defconstant mt19937-m 397)
-(defconstant mt19937-upper-mask #x80000000)
-(defconstant mt19937-lower-mask #x7fffffff)
-(defconstant mt19937-b #x9D2C5680)
-(defconstant mt19937-c #xEFC60000)
-;;;
-#-x86
@@ -266 +250,0 @@
-#-x86
@@ -285,8 +268,0 @@
-;;; Using inline VOP support, only available on the x86 so far.
-#+x86
-(defun random-chunk (state)
-  (declare (type random-state state))
-  (vm::random-mt19937 (random-state-state state)))
-
-
-

@@ -295,4 +270,0 @@
-;;;    Handle the single or double float case of RANDOM.  We generate a float
-;;; between 0.0 and 1.0 by clobbering the significand of 1.0 with random bits,
-;;; then subtracting 1.0.  This hides the fact that we have a hidden bit.
-;;;
@@ -304,10 +275,0 @@
-(defun %random-single-float (arg state)
-  (declare (type (single-float (0f0)) arg)
-          (type random-state state))
-  (* arg
-     (- (make-single-float
-        (dpb (ash (random-chunk state)
-                  (- vm:single-float-digits random-chunk-length))
-             vm:single-float-significand-byte
-             (single-float-bits 1.0)))
-       1.0)))
@@ -319,7 +280,0 @@
-;;; 32bit version
-;;;
-#+nil
-(defun %random-double-float (arg state)
-  (declare (type (double-float (0d0)) arg)
-          (type random-state state))
-  (* (float (random-chunk state) 1d0) (/ 1d0 (expt 2 32))))
@@ -327,15 +282,8 @@
-;;; 53bit version.
-;;;
-#-x86
-(defun %random-double-float (arg state)
-  (declare (type (double-float (0d0)) arg)
-          (type random-state state))
-  (* arg
-     (- (lisp::make-double-float
-        (dpb (ash (random-chunk state)
-                  (- vm:double-float-digits random-chunk-length
-                     vm:word-bits))
-             vm:double-float-significand-byte
-             (lisp::double-float-high-bits 1d0))
-        (random-chunk state))
-       1d0)))
+(defun %random-single-float (arg state)
+  "Handle the single or double float case of RANDOM.  We generate a float
+  in [0f0, 1f0) by clobbering the mantissa of 1f0 with random bits (23 bits);
+  this yields a number in [1f0, 2f0). Then 1f0 is subtracted."
+  (let*
+    ((random-mantissa-bits (%random-integer (expt 2 23) state))
+    (random-unit-float (- (scale-float (float (+ (expt 2 23) random-mantissa-bits) 1f0) -23) 1f0)))
+  (* arg random-unit-float)))
@@ -343,2 +290,0 @@
-;;; Using a faster inline VOP.
-#+x86
@@ -346,41 +292,7 @@
-  (declare (type (double-float (0d0)) arg)
-          (type random-state state))
-  (let ((state-vector (random-state-state state)))
-    (* arg
-       (- (lisp::make-double-float
-          (dpb (ash (vm::random-mt19937 state-vector)
-                    (- vm:double-float-digits random-chunk-length
-                       vm:word-bits))
-               vm:double-float-significand-byte
-               (lisp::double-float-high-bits 1d0))
-          (vm::random-mt19937 state-vector))
-         1d0))))
-
-#+long-float
-(declaim (inline %random-long-float))
-#+long-float
-(declaim (ftype (function ((long-float (0l0)) random-state) (long-float 0l0))
-               %random-long-float))
-
-;;; Using a faster inline VOP.
-#+(and long-float x86)
-(defun %random-long-float (arg state)
-  (declare (type (long-float (0l0)) arg)
-          (type random-state state))
-  (let ((state-vector (random-state-state state)))
-    (* arg
-       (- (lisp::make-long-float
-          (lisp::long-float-exp-bits 1l0)
-          (logior (vm::random-mt19937 state-vector) vm:long-float-hidden-bit)
-          (vm::random-mt19937 state-vector))
-         1l0))))
-
-#+(and long-float sparc)
-(defun %random-long-float (arg state)
-  (declare (type (long-float (0l0)) arg)
-          (type random-state state))
-  (* arg
-     (- (lisp::make-long-float
-        (lisp::long-float-exp-bits 1l0)        ; X needs more work
-        (random-chunk state) (random-chunk state) (random-chunk state))
-       1l0)))
+  "Handle the single or double float case of RANDOM.  We generate a float
+  in [0d0, 1d0) by clobbering the mantissa of 1d0 with random bits (52 bits);
+  this yields a number in [1d0, 2d0). Then 1d0 is subtracted."
+  (let*
+    ((random-mantissa-bits (%random-integer (expt 2 52) state))
+    (random-unit-double (- (scale-float (float (+ (expt 2 52) random-mantissa-bits) 1d0) -52) 1d0)))
+  (* arg random-unit-double)))
@@ -388 +299,0 @@
-

@@ -391,16 +301,0 @@
-;;; Amount we overlap chunks by when building a large integer to make up for
-;;; the loss of randomness in the low bits.
-;;;
-(defconstant random-integer-overlap 3)
-
-;;; Extra bits of randomness that we generate before taking the value MOD the
-;;; limit, to avoid loss of randomness near the limit.
-;;;
-(defconstant random-integer-extra-bits 10)
-
-;;; Largest fixnum we can compute from one chunk of bits.
-;;;
-(defconstant random-fixnum-max
-  (1- (ash 1 (- random-chunk-length random-integer-extra-bits))))
-
-
@@ -409,0 +305,7 @@
+  "Generates an integer greater than or equal to zero and less than Arg.
+  Successive chunks are concatenated without overlap to construct integers
+  larger than a single chunk. The return value has this property:
+  If two integers are generated from the same state with Arg equal to 2^m and 2^n,
+  respectively, then bit k is the same in both integers for 0 <= k < min(m,n).
+  Each call to %RANDOM-INTEGER consumes at least one chunk; bits left over
+  from previous chunks are not re-used."
@@ -411,9 +313,7 @@
-  (let ((shift (- random-chunk-length random-integer-overlap)))
-    (do ((bits (random-chunk state)
-              (logxor (ash bits shift) (random-chunk state)))
-        (count (+ (integer-length arg)
-                  (- random-integer-extra-bits shift))
-               (- count shift)))
-       ((minusp count)
-        (rem bits arg))
-      (declare (fixnum count)))))
+    (do*
+      ((nchunks (ceiling (integer-length (1- arg)) random-chunk-length) (1- nchunks))
+        (new-bits 0 (random-chunk state))
+        (bits 0 (logior bits (ash new-bits shift)))
+        (shift 0 (+ shift random-chunk-length)))
+      ((= 0 nchunks)
+        (rem bits arg))))
@@ -422,4 +322,3 @@
-  "Generate a uniformly distributed pseudo-random number between zero
-  and Arg.  State, if supplied, is the random state to use."
-  (declare (inline %random-single-float %random-double-float
-                  #+long-float %long-float))
+  "Generates a uniformly distributed pseudo-random number greater than or equal to zero
+  and less than Arg.  State, if supplied, is the random state to use."
+  (declare (inline %random-single-float %random-double-float))
@@ -427,2 +325,0 @@
-    ((and (fixnump arg) (<= arg random-fixnum-max) (> arg 0))
-     (rem (random-chunk state) arg))
@@ -433,3 +329,0 @@
-    #+long-float
-    ((and (typep arg 'long-float) (> arg 0.0L0))
-     (%random-long-float arg state))
@@ -442,0 +337,27 @@
+
+;;; begin Maxima-specific stuff
+
+(in-package "MAXIMA")
+
+(defmfun $set_random_state (x)
+  "Copy the argument, and assign the copy to MT19937::*RANDOM-STATE*.
+  Returns '$done."
+  (setq mt19937::*random-state* (mt19937::make-random-state x))
+  '$done)
+
+(defmfun $make_random_state (x)
+  "Returns a new random state object. If argument is an integer or array,
+  use argument to initialize random state. Otherwise punt to MT19937::MAKE-RANDOM-STATE."
+  (cond
+    ((or (integerp x) (arrayp x))
+      (mt19937::make-random-object :state (mt19937::init-random-state x)))
+    (t
+      (mt19937::make-random-state x))))
+
+(defmfun $random (x)
+  "Returns the next number from this generator.
+  Punt to MT19937::RANDOM."
+  (mt19937::random x))
+
+;;; end Maxima-specific stuff
+