2022-04-07 18:33:05 +02:00

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))))