packages feed

flower-0.1.2: src/Statistics.hs

-- | Yet another simple module for implementing statistics stuff.

module Statistics (normal, normals, stdnormal, stdnormals, module System.Random) where
import System.Random

stdnormal :: StdGen -> (Double,StdGen)
stdnormal = normal 0 1

stdnormals :: StdGen -> [Double]
stdnormals = normals 0 1

normal :: Double -> Double -> StdGen -> (Double,StdGen)
normal mu sigma = \g -> let (x,g') = randomR (0,1) g in (invcumnorm mu sigma x,g') 

normals :: Double -> Double -> StdGen -> [Double]
normals mu sigma = \g -> let (x,g') = normal mu sigma g in x : normals mu sigma g'

lognormal :: Double -> Double -> StdGen -> Double
lognormal mu sigma = undefined

-- support

invcumnorm mu sigma z = mu + search (-limit*sigma) (limit*sigma)
    where search a b = let c = (a+b)/2
                           cn = cumnorm 0 sigma c
                       in if abs (z - cn) < 10*epsilon || abs (a-b) < epsilon then c
                            else if cn > z then search a c
                                 else search c b

cumstdnorm :: Double -> Double
cumstdnorm x = 0.5*(1+erf (x/sqrt 2))

cumnorm :: Double -> Double -> Double -> Double
cumnorm mu sigma x = 0.5*(1+erf((x-mu)/(sigma*sqrt 2)))

-- taylor expansion, see wikipedia "error function".  Tested within the range (-limit..limit)
erf :: Double -> Double
erf x | x>limit         = 1
      | x< negate limit = 0
      | otherwise   = (2/sqrt pi)*sum (reverse $ takeWhile ((>=epsilon).abs) [ ((-1)**n*x**(2*n+1)) / (fac n*(2*n+1)) | n <- [0..]])

epsilon = 0.0000000001
limit = 4.4 :: Double
fac x = product [2..x]