random-fu-0.0.0.2: src/Data/Random/Distribution/Normal.hs
{-
- ``Data/Random/Distribution/Normal''
-
- Quick and dirty implementation - eventually something faster probably
- ought to be implemented instead.
-}
{-# LANGUAGE
MultiParamTypeClasses, FlexibleInstances, FlexibleContexts,
UndecidableInstances
#-}
module Data.Random.Distribution.Normal where
import Data.Random.Source
import Data.Random.Distribution
import Data.Random.Distribution.Uniform
import Data.Random.RVar
import Control.Monad
-- Box-Muller method
normalPair :: (Floating a, Distribution Uniform a) => RVar (a,a)
normalPair = do
u <- uniform 0 1
t <- uniform 0 (2 * pi)
let r = sqrt (-2 * log u)
x = r * cos t
y = r * sin t
return (x,y)
-- slightly slower
knuthPolarNormalPair :: (Floating a, Ord a, Distribution Uniform a) => RVar (a,a)
knuthPolarNormalPair = do
v1 <- uniform (-1) 1
v2 <- uniform (-1) 1
let s = v1*v1 + v2*v2
if s >= 1
then knuthPolarNormalPair
else return $ if s == 0
then (0,0)
else let scale = sqrt (-2 * log s / s)
in (v1 * scale, v2 * scale)
realFloatStdNormal :: RealFloat a => RVar a
realFloatStdNormal = do
u <- realFloatStdUniform
t <- realFloatStdUniform
let r = sqrt (-2 * log u)
x = r * cos (t * 2 * pi)
return x
data Normal a
= StdNormal
| Normal a a -- mean, sd
instance (Floating a, Distribution Uniform a) => Distribution Normal a where
rvar StdNormal = liftM fst normalPair
rvar (Normal m s) = do
x <- liftM fst normalPair
return (x * s + m)
stdNormal :: Distribution Normal a => RVar a
stdNormal = rvar StdNormal
normal :: Distribution Normal a => a -> a -> RVar a
normal m s = rvar (Normal m s)