(module gaussian mzscheme
(require (lib "contract.ss"))
(provide/contract
(random-gaussian
(case-> (-> random-source? real? (>=/c 0.0) real?)
(-> real? (>=/c 0.0) real?)))
(random-unit-gaussian
(case-> (-> random-source? real?)
(-> real?)))
(random-gaussian-ratio-method
(case-> (-> random-source? real? (>=/c 0.0) real?)
(-> real? (>=/c 0.0) real?)))
(random-unit-gaussian-ratio-method
(case-> (-> random-source? real?)
(-> real?)))
(gaussian-pdf
(-> real? real? (>=/c 0.0) (>=/c 0.0)))
(unit-gaussian-pdf
(-> real? (>=/c 0.0)))
(gaussian-cdf
(-> real? real? (>=/c 0.0) (real-in 0.0 1.0)))
(unit-gaussian-cdf
(-> real? (real-in 0.0 1.0))))
(require "../math.ss")
(require "../random-source.ss")
(require "../special-functions/error.ss")
(define random-gaussian
(case-lambda
((r mu sigma)
(if (not (random-source? r))
(raise-type-error 'random-gaussian
"random-source" r))
(if (not (real? mu))
(raise-type-error 'random-gaussian
"real" mu))
(if (not (real? sigma))
(raise-type-error 'random-gaussian
"real" sigma))
(let ((x 0.0)
(y 0.0)
(r2 0.0))
(let loop ()
(set! x (+ -1.0 (* 2.0 (random-uniform r))))
(set! y (+ -1.0 (* 2.0 (random-uniform r))))
(set! r2 (+ (* x x) (* y y)))
(if (> r2 1.0)
(loop)))
(+ mu (* sigma y (sqrt (/ (* -2.0 (log r2)) r2))))))
((mu sigma)
(random-gaussian (current-random-source) mu sigma))))
(define random-unit-gaussian
(case-lambda
((r)
(if (not (random-source? r))
(raise-type-error 'random-unit-gaussian
"random-source" r))
(random-gaussian r 0.0 1.0))
(()
(random-unit-gaussian (current-random-source)))))
(define random-gaussian-ratio-method
(case-lambda
((r mu sigma)
(if (not (random-source? r))
(raise-type-error 'random-gaussian-ratio-method
"random-source" r))
(if (not (real? mu))
(raise-type-error 'random-gaussian-ratio-method
"real" mu))
(if (not (real? sigma))
(raise-type-error 'random-gaussian-ratio-method
"real" sigma))
(let ((u 0.0)
(v 0.0)
(x 0.0))
(let loop ()
(set! v (random-uniform r))
(set! u (random-uniform r))
(set! x (/ (* 1.71552776992141359295 (- v 0.5)) u))
(if (> (* x x)
(* -4.0 (log u)))
(loop)))
(+ mu (* sigma x))))
((mu sigma)
(random-gaussian-ratio-method (current-random-source) mu sigma))))
(define random-unit-gaussian-ratio-method
(case-lambda
((r)
(if (not (random-source? r))
(raise-type-error 'random-unit-gaussian-ratio-method
"random-source" r))
(random-gaussian-ratio-method r 0.0 1.0))
(()
(random-unit-gaussian-ratio-method (current-random-source)))))
(define (gaussian-pdf x mu sigma)
(if (not (real? x))
(raise-type-error 'gaussion-pdf
"real" x))
(if (not (real? mu))
(raise-type-error 'gaussian-pdf
"real" mu))
(if (not (real? sigma))
(raise-type-error 'gaussian-pdf
"real" sigma))
(* (/ 1.0 (* sigma (sqrt (* 2.0 pi))))
(exp (/ (- (* (- x mu) (- x mu)))
(* 2.0 sigma sigma)))))
(define (unit-gaussian-pdf x)
(if (not (real? x))
(raise-type-error 'unit-gaussian-pdf
"real" x))
(gaussian-pdf x 0.0 1.0))
(define (gaussian-cdf x mu sigma)
(if (not (real? x))
(raise-type-error 'gaussion-cdf
"real" x))
(if (not (real? mu))
(raise-type-error 'gaussian-cdf
"real" mu))
(if (not (real? sigma))
(raise-type-error 'gaussian-cdf
"real" sigma))
(/ (+ 1.0 (erf (/ (- x mu) (* sigma (sqrt 2.0))))) 2.0))
(define (unit-gaussian-cdf x)
(if (not (real? x))
(raise-type-error 'unit-gaussian-cdf
"real" x))
(gaussian-cdf x 0.0 1.0))
)