(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 "../machine.ss")
(require "../math.ss")
(require "../random-source.ss")
(require "../special-functions/error.ss")
(define random-gaussian
(case-lambda
((r mu 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)
(random-gaussian r 0.0 1.0))
(()
(random-unit-gaussian (current-random-source)))))
(define random-gaussian-ratio-method
(case-lambda
((r mu 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)
(random-gaussian-ratio-method r 0.0 1.0))
(()
(random-unit-gaussian-ratio-method (current-random-source)))))
(define (gaussian-pdf x mu sigma)
(* (/ 1.0 (* sigma (sqrt (* 2.0 pi))))
(exp (/ (- (* (- x mu) (- x mu)))
(* 2.0 sigma sigma)))))
(define (unit-gaussian-pdf x)
(gaussian-pdf x 0.0 1.0))
(define gauss-epsilon (/ double-epsilon 2.0))
(define gauss-xupper 8.572)
(define gauss-xlower -37.519)
(define gauss-scale 16.0)
(define (get-del x rational)
(let ((xsq (/ (floor (* x gauss-scale)) gauss-scale))
(del 0.0))
(set! del (* (- x xsq) (+ x xsq)))
(set! del (* del 0.5))
(* (exp (* -0.5 xsq xsq)) (exp (* -1.0 del)) rational)))
(define (gauss-small x)
(define a '#(2.2352520354606839287
161.02823106855587881
1067.6894854603709582
18154.981253343561249
0.065682337918207449113))
(define b '#(47.20258190468824187
976.09855173777669322
10260.932208618978205
45507.789335026729956))
(let* ((xsq (* x x))
(xnum (* (vector-ref a 4) xsq))
(xden xsq))
(do ((i 0 (+ i 1)))
((= i 3) (/ (* x (+ xnum (vector-ref a 3)))
(+ xden (vector-ref b 3))))
(set! xnum (* (+ xnum (vector-ref a i)) xsq))
(set! xden (* (+ xden (vector-ref b i)) xsq)))))
(define (gauss-medium x)
(define c '#(0.39894151208813466764
8.8831497943883759412
93.506656132177855979
597.27027639480026226
2494.5375852903726711
6848.1904505362823326
11602.651437647350124
9842.7148383839780218
1.0765576773720192317e-8))
(define d '#(22.266688044328115691
235.38790178262499861
1519.377599407554805
6485.558298266760755
18615.571640885098091
34900.952721145977266
38912.003286093271411
19685.429676859990727))
(let* ((absx (abs x))
(xnum (* (vector-ref c 8) absx))
(xden absx)
(temp 0.0))
(do ((i 0 (+ i 1)))
((= i 7) (void))
(set! xnum (* (+ xnum (vector-ref c i)) absx))
(set! xden (* (+ xden (vector-ref d i)) absx)))
(set! temp (/ (+ xnum (vector-ref c 7))
(+ xden (vector-ref d 7))))
(get-del x temp)))
(define (gauss-large x)
(define p '#(0.21589853405795699
0.1274011611602473639
0.022235277870649807
0.001421619193227893466
2.9112874951168792e-5
0.02307344176494017303))
(define q '#(1.28426009614491121
0.468238212480865118
0.0659881378689285515
0.00378239633202758244
7.29751555083966205e-5))
(let* ((absx (abs x))
(xsq (/ 1.0 (* x x)))
(xnum (* (vector-ref p 5) xsq))
(xden xsq)
(temp 0.0))
(do ((i 0 (+ i 1)))
((= i 4)(void))
(set! xnum (* (+ xnum (vector-ref p i)) xsq))
(set! xden (* (+ xden (vector-ref q i)) xsq)))
(set! temp (/ (* xsq (+ xnum (vector-ref p 4)))
(+ xden (vector-ref q 4))))
(set! temp (/ (- (/ sqrt1/2 sqrtpi) temp) absx))
(get-del x temp)))
(define (unit-gaussian-cdf x)
(let ((absx (abs x)))
(cond ((< absx gauss-epsilon)
0.5)
((< absx 0.66291)
(+ 0.5 (gauss-small x)))
((< absx (sqrt 32.0))
(let ((result (gauss-medium x)))
(if (> x 0.0)
(- 1.0 result)
result)))
((> x gauss-xupper)
1.0)
((< x gauss-xlower)
0.0)
(else
(let ((result (gauss-large x)))
(if (> x 0.0)
(- 1.0 result)
result))))))
(define (gaussian-cdf x mu sigma)
(unit-gaussian-cdf (/ (- x mu) sigma)))
)