-- $Id: moments.ghc,v 1.1 2001/02/14 22:12:21 doug Exp $
-- http://www.bagley.org/~doug/shootout/
-- from Brian Gregor

module Main where

import IO 
import System
import Numeric

-- read the file
main = do input <- getContents
      putAns (lines input)         
        

-- print out the answers
putAns :: [String] -> IO ()
putAns st_nums = do
               putStrLn ("n:                  " ++ (showInt (truncate n) ""))
                   putStrLn ("median:             " ++ (showFFloat (Just 6) (median nums n) ""))
           putStrLn ("mean:               " ++ (showFFloat (Just 6) mean ""))
           putStrLn ("average_deviation:  " ++ (showFFloat (Just 6) avg_dev ""))
           putStrLn ("standard_deviation: " ++ (showFFloat (Just 6) std_dev ""))
           putStrLn ("variance:           " ++ (showFFloat (Just 6) var ""))
           putStrLn ("skew:               " ++ (showFFloat (Just 6) skew ""))
           putStrLn ("kurtosis:           " ++ (showFFloat (Just 6) kurt ""))
                 where
             n = fromIntegral (length nums)
           nums = strToDoub st_nums
           mean = (sum nums) / n
           deviation = [x-mean | x <- nums] 
           avg_dev = (sum [abs x | x <- deviation])/ n
           var = (sum [x**2 | x <- deviation]) / (n-1)
           std_dev = sqrt var
           skew = (sum [x**3 | x <- deviation]) / (n*var*std_dev)
           kurt = (sum [x**4 | x <- deviation]) / (n*var*var)-3.0


-- convert the strings to doubles
strToDoub :: [String] -> [Double]
strToDoub nums = map conv nums
    where  conv x = fst (head (readFloat x))

-- calculate the median
median :: [Double] -> Double -> Double
median nums n = mid (mSort nums)
       where 
         mid x 
           | odd (length x) = x!! midpt
           | otherwise       = ((x!!(midpt-1)) + (x!!midpt)) / 2.0
         midpt :: Int
         midpt = floor (n/2) 

-- Sorting: the various languages use various algorithms
-- here's  an optimized mergesort from 
-- "Algorithms - a Functional Approach" by
-- Fethi Rabhe & Guy Lapalme
split :: (Ord a) => [a] -> [[a]]
split [] = []
split (x:xs) = [x]:split xs

merge :: (Ord a) => [a] -> [a] -> [a]
merge [] b  = b
merge a [] = a
merge a@(x:xs) b@(y:ys)
    | (x<=y) = x : (merge xs b)
    | otherwise = y : (merge a ys)

mergepairs :: (Ord a) => [[a]] -> [[a]]
mergepairs [] = []
mergepairs x@[l] = x
mergepairs (l1:l2:rest) = (merge l1 l2) : (mergepairs $! rest)

-- The actual sort
mSort :: (Ord a) => [a] -> [a]
mSort l = ms (split l)
    where  ms [r] = r
           ms l   = ms (mergepairs l)