(* -*- mode: sml -*-
* $Id: moments.smlnj,v 1.3 2001/07/10 12:55:23 doug Exp $
* http://www.bagley.org/~doug/shootout/
* from Stephen Weeks
* with help from Daniel Wang:
* Modified to be more functional and use SML/NJ library sorting function
*)
structure Test : sig
val main : (string * string list) -> OS.Process.status
end = struct
val ins = TextIO.stdIn
fun loop (nums,sum) =
case TextIO.inputLine ins of
"" => (nums,sum)
| l => (case Real.fromString l of
NONE => raise Fail "invalid input"
| SOME num => loop(num::nums,sum+num))
fun printl [] = print "\n" | printl(h::t) = ( print h ; printl t )
fun r2s (x: real): string =
if Real.== (x, 0.0) then "0.000000"
else String.translate
(fn #"~" => "-" | c => str c)
(Real.fmt (StringCvt.FIX (SOME 6)) x)
fun main(name, args) = let
val (nums,sum) = loop ([],0.0)
val nums = Array.fromList nums
val n = Array.length nums
val n_float = real n
val mean = sum / n_float
fun moments (x,{average_deviation,variance,skew,kurtosis}) = let
val deviation = x - mean
val average_deviation =
average_deviation + abs(deviation)
val dev2 = deviation * deviation
val variance = variance + dev2
val dev3 = dev2 * deviation
val skew = skew + dev3
val dev4 = dev3 * deviation
val kurtosis = kurtosis + dev4
in {average_deviation=average_deviation,
variance=variance,
skew=skew,
kurtosis=kurtosis}
end
val init = {average_deviation=0.0,
variance=0.0,
skew=0.0,
kurtosis=0.0}
val {average_deviation,variance,skew,kurtosis} =
Array.foldl moments init nums
val average_deviation = average_deviation / n_float
val variance = variance / real (n - 1);
val standard_deviation = Real.Math.sqrt (variance)
val {skew,kurtosis} =
if variance > 0.0
then {skew=skew / n_float / variance / standard_deviation,
kurtosis=kurtosis / n_float / variance / variance - 3.0}
else {skew=skew,kurtosis=kurtosis}
val _ = ArrayQSort.sort Real.compare nums
val mid = Int.quot (n, 2)
val median =
if Int.rem (n, 2) = 1
then Array.sub (nums, mid)
else (Array.sub (nums, mid) +
Array.sub (nums, mid - 1)) / 2.0
in
printl ["n: ", Int.toString n, "\n",
"median: ", r2s median, "\n",
"mean: ", r2s mean, "\n",
"average_deviation: ", r2s average_deviation, "\n",
"standard_deviation: ", r2s standard_deviation, "\n",
"variance: ", r2s variance, "\n",
"skew: ", r2s skew, "\n",
"kurtosis: ", r2s kurtosis];
OS.Process.success
end
end
val _ = SMLofNJ.exportFn("moments", Test.main);