RNG - mimic Java's Util.Random (#1672)

* initial java Util.Random mimic

* add comment referencing java impl

* fix 64 bit stuff

* copy scf-time definition into math.gc, use for initial seed

* rename java -> knuth

* move knuth-rand to separate file

* move knuth-rand to separate file

* PR comments
This commit is contained in:
Matt Dallmeyer 2022-07-29 17:04:22 -07:00 committed by GitHub
parent d53f0ccd35
commit a04bdff80d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 3 deletions

View file

@ -6287,7 +6287,6 @@
:flag-assert #x900000008
)
;; ----------------------
;; File - capture
;; Source Path - engine/gfx/capture.gc

View file

@ -51,6 +51,7 @@
("connect.o" "connect")
("text-h.o" "text-h")
("settings-h.o" "settings-h")
("knuth-rand.o" "knuth-rand") ;; added
("capture.o" "capture")
("memory-usage-h.o" "memory-usage-h")
("texture.o" "texture")

View file

@ -47,6 +47,7 @@
("connect.o" "connect")
("text-h.o" "text-h")
("settings-h.o" "settings-h")
("knuth-rand.o" "knuth-rand") ;; added
("capture.o" "capture")
("memory-usage-h.o" "memory-usage-h")
("texture.o" "texture")

View file

@ -233,3 +233,21 @@
)
(define-extern *setting-control* setting-control)
(defun scf-time-to-uint64 ()
(let ((date (new 'stack 'scf-time)))
(let ((temp (the uint64 0)))
(scf-get-time date)
(logior! temp (-> date stat))
(logior! temp (shl (-> date second) 8))
(logior! temp (shl (-> date minute) 16))
(logior! temp (shl (-> date hour) 24))
(logior! temp (shl (-> date week) 32))
(logior! temp (shl (-> date day) 40))
(logior! temp (shl (-> date month) 48))
(logior! temp (shl (-> date year) 56))
temp
)
)
)

View file

@ -0,0 +1,71 @@
;;-*-Lisp-*-
(in-package goal)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; mimicking Java's util.Random https://docs.oracle.com/javase/8/docs/api/java/util/Random.html
;;;; This is a linear congruential pseudorandom number generator, as defined by D. H. Lehmer
;;;; and described by Donald E. Knuth in The Art of Computer Programming, Volume 3: Seminumerical Algorithms, section 3.2.1.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftype knuth-rand-state (structure)
((seed uint64))
)
(define *knuth-rand-state* (new 'global 'knuth-rand-state))
(defun knuth-rand-init ((newSeed uint))
(set! (-> *knuth-rand-state* seed) newSeed)
)
(knuth-rand-init (scf-time-to-uint64))
(defun knuth-rand-advance-seed ()
;; seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
(set! (-> *knuth-rand-state* seed) (the uint64 (logand (+ (imul64 (-> *knuth-rand-state* seed) 25214903917) 11) (- (shl 1 48) 1))))
)
(defun knuth-rand-next ((bits int))
(knuth-rand-advance-seed)
;; return (int)(seed >>> (48 - bits))
(shr (-> *knuth-rand-state* seed) (- 48 bits))
)
(defun knuth-rand-nextInt ()
(knuth-rand-advance-seed)
(-> *knuth-rand-state* seed)
)
;; returns a pseudorandom int in the range [min, max)
(defun knuth-rand-nextIntRange ((min int) (max int))
(let* ((bound (- max min))
;; int bits, val;
(bits (the uint64 0))
(val (the uint64 0)))
;; if ((bound & -bound) == bound) // i.e., bound is a power of 2
(if (= (logand bound (* -1 bound)) bound)
;; return (int)((bound * (long)next(31)) >> 31);
(return (sar (* bound (knuth-rand-next 31)) 31))
)
;; do {
;; bits = next(31);
;; val = bits % bound;
;; } while (bits - val + (bound-1) < 0);
;; return val;
(while #t
(set! bits (knuth-rand-next 31))
(set! val (mod bits bound))
(if (>= (+ bits (* -1 val) bound -1) 0)
(return (+ min val))
)
)
)
-1
)
;; returns a pseudorandom float in the range [0, 1)
(defun knuth-rand-nextFloat ()
;; return next(24) / ((float)(1 << 24));
(/ (the float (knuth-rand-next 24)) (shl 1 24))
)

View file

@ -315,5 +315,4 @@
(defmacro rand-float-gen (&key (gen *random-generator*))
"Generate a float from [0, 1)"
`(+ -1.0 (the-as float (logior #x3f800000 (/ (rand-uint31-gen ,gen) 256))))
)
)

View file

@ -1696,6 +1696,7 @@
"engine/connect.gc"
"ui/text-h.gc"
"game/settings-h.gc"
"math/knuth-rand.gc" ;; added
"util/capture.gc"
"debug/memory-usage-h.gc"
"gfx/texture/texture.gc"