68 lines
2.0 KiB
Scheme
68 lines
2.0 KiB
Scheme
;; In Emacs, open this file in -*- Scheme -*- mode.
|
|
|
|
;; A PCG random number generator. (Specifically, this is the variant
|
|
;; called XSH RR in the paper, with a 16-bit state and 8-bit output).
|
|
;; See http://www.pcg-random.org/
|
|
|
|
(def %rng-to-uint16
|
|
(fun (i) (int-bitwise-and #xFFFF i)))
|
|
|
|
(def %rng-to-uint8
|
|
(fun (i) (int-bitwise-and #xFF i)))
|
|
|
|
(def rng-make
|
|
(fun (seed)
|
|
(let ((rng (@block-alloc-50 1)))
|
|
(@block-set! rng 0 (%rng-to-uint16 seed))
|
|
rng)))
|
|
|
|
(def rng?
|
|
(fun (o)
|
|
(and (@block? o) (= (@block-tag o) 50))))
|
|
|
|
(def %rng-get-state
|
|
(fun (rng)
|
|
(@block-get rng 0)))
|
|
|
|
(def %rng-set-state!
|
|
(fun (rng new-state)
|
|
(@block-set! rng 0 (%rng-to-uint16 new-state))))
|
|
|
|
(def %rng-rotate-right-8
|
|
(fun (x y)
|
|
(%rng-to-uint8 (int-bitwise-or (int-shift-right x y)
|
|
(int-shift-left x (- 8 y))))))
|
|
|
|
(def %rng-step
|
|
(fun (rng)
|
|
(%rng-set-state! rng (+ (* (%rng-get-state rng) 12829) 47989))))
|
|
|
|
(def %rng-output
|
|
(fun (rng)
|
|
(let ((state (%rng-get-state rng)))
|
|
(%rng-rotate-right-8
|
|
(%rng-to-uint8 (int-shift-right
|
|
(int-bitwise-xor state (int-shift-right state 5))
|
|
5))
|
|
(int-shift-right state 13)))))
|
|
|
|
;; Return the next 8-bit unsigned integer (0 to 255, included)
|
|
(def rng-next-int8
|
|
(fun (rng)
|
|
(let ((i (%rng-output rng)))
|
|
(%rng-step rng)
|
|
i)))
|
|
|
|
;; FIXME: this is hackish, find a better way to do it (probably using
|
|
;; multiple streams, see sample/pcg32x2-demo.c in the PCG source).
|
|
(def rng-next-int
|
|
(fun (rng)
|
|
(let ((b0 (rng-next-int8 rng))
|
|
(b1 (rng-next-int8 rng))
|
|
(b2 (rng-next-int8 rng))
|
|
(b3 (rng-next-int8 rng)))
|
|
(int-bitwise-or (int-shift-left b0 24)
|
|
(int-shift-left b1 16)
|
|
(int-shift-left b2 8)
|
|
b3))))
|