src/random-numbers.lisp @ 50ab2f9c5b2f

Initial commit
author Steve Losh <steve@stevelosh.com>
date Wed, 06 Jul 2016 18:29:38 +0000
parents (none)
children 277982735a9d
(in-package #:sand.random-numbers)


(declaim (optimize (speed 1) (safety 1) (debug 3)))

(deftype positive-fixnum () `(integer 1 ,most-positive-fixnum))
(deftype negative-fixnum () `(integer ,most-negative-fixnum -1))
(deftype nonnegative-fixnum () `(integer 1 ,most-positive-fixnum))
(deftype nonpositive-fixnum () `(integer ,most-negative-fixnum -1))

(defun* +mod ((x nonnegative-fixnum)
              (y nonnegative-fixnum)
              (m positive-fixnum))
  (if (<= x (- m 1 y))
    (+ x y)
    (- x (- m y))))


(defun* make-linear-congruential-rng
    ((modulus positive-fixnum)
     (multiplier nonnegative-fixnum)
     (increment nonnegative-fixnum)
     (seed nonnegative-fixnum))
  (let ((val seed))
    (lambda (incr)
      (loop :repeat incr :do
            (setf val (mod (+ (* multiplier val)
                              increment)
                           modulus))))))

(defun* make-linear-congruential-rng-fast%
    ((modulus positive-fixnum)
     (multiplier nonnegative-fixnum)
     (increment nonnegative-fixnum)
     (seed nonnegative-fixnum))
  (declare (optimize (speed 3) (safety 0) (debug 0)))
  (let ((val seed))
    (lambda (incr)
      (declare (positive-fixnum incr))
      (loop :repeat incr :do
            (setf val (mod (+ (the nonnegative-fixnum (* multiplier val))
                              increment)
                           modulus))))))

(define-compiler-macro make-linear-congruential-rng
    (&whole form
     modulus multiplier increment seed)
  (if (and (constantp modulus)
           (constantp multiplier)
           (<= (* multiplier (1- modulus))
               most-positive-fixnum))
    `(make-linear-congruential-rng-fast% ,modulus ,multiplier ,increment ,seed)
    form))


(defun dammit () (make-linear-congruential-rng 50 2 3 2))
(defparameter *r* (dammit))
(disassemble *r*)

(defparameter m 40)

(defun run ()
  (let ((r (make-linear-congruential-rng 50 2 3 2)))
    (disassemble r)
    (funcall r 100000000)))

(time (run))