package utils; import java.util.*; import java.io.*; /** This class is used to model the statistics of a set of numbers. For the statistics we choose here it is not necessary to store all the numbers - just keeping a running total of how many, the sum and the sum of the squares is sufficient (plus max and min, for max and min). */ public class StatisticalSummary implements java.io.Serializable { // a temporary fix for an immediate need // this should really be handled with a more general // predicate class public static class Watch { double x; public int count; public Watch(double x) { this.x = x; count = 0; } public void note(double val) { if ( val == x ) { count++; } } public String toString() { return x + " occured " + count + " times "; } public void reset() { count = 0; } } // following line can cause prog to hang - bug in Java? // protected long serialVersionUID = new Double("-1490108905720833569").longValue(); protected long serialVersionUID = 123; public String name; // defaults to "" private double sum; private double sumsq; private double min; private double max; private double mean; private double sd; int n; boolean valid; public Watch watch; public StatisticalSummary() { this(""); // System.err.println("Exited default..."); } public StatisticalSummary(String name) { // System.err.println("Creating SS"); this.name = name; n = 0; sum = 0; sumsq = 0; // ensure that the first number to be // added will set up min and max to // be that number min = Double.POSITIVE_INFINITY; max = Double.NEGATIVE_INFINITY; // System.err.println("Finished Creating SS"); watch = null; valid = false; } public final void reset() { n = 0; sum = 0; sumsq = 0; // ensure that the first number to be // added will set up min and max to // be that number min = Double.POSITIVE_INFINITY; max = Double.NEGATIVE_INFINITY; if (watch!= null) { watch.reset(); } } public double max() { return max; } public double min() { return min; } public double mean() { if (!valid) computeStats(); return mean; } /** returns the sum of the squares of the differences between the mean and the ith values */ public double sumSquareDiff() { return sumsq - n * mean() * mean(); } private void computeStats() { if (!valid) { mean = sum / n; double num = sumsq - (n * mean * mean); if (num < 0) { // avoids tiny negative numbers possible through imprecision num = 0; } // System.err.println("Num = " + num); sd = Math.sqrt(num / (n - 1)); // System.err.println(" Test: sd = " + sd); // System.err.println(" Test: n = " + n); valid = true; } } public double sd() { if (!valid) computeStats(); return sd; } public int n() { return n; } public double stdErr() { return sd() / Math.sqrt(n); } public void add(StatisticalSummary ss) { // implications for Watch? n += ss.n; sum += ss.sum; sumsq += ss.sumsq; max = Math.max(max, ss.max); min = Math.min(min, ss.min); valid = false; } public void add(double d) { n++; sum += d; sumsq += d * d; min = Math.min(min, d); max = Math.max(max, d); if (watch != null) { watch.note( d ); } valid = false; } public void add(Number n) { add(n.doubleValue()); } public void add(double[] d) { for (int i = 0; i < d.length; i++) { add(d[i]); } } public void add(Vector v) { for (int i = 0; i < v.size(); i++) { try { add(((Number) v.elementAt(i)).doubleValue()); } catch (Exception e) { } } } public String toString() { return " min = " + min() + "\n" + " max = " + max() + "\n" + " ave = " + mean() + "\n" + " sd = " + sd() + "\n" + " se = " + stdErr() + "\n" + " sum = " + sum + "\n" + " sumsq = " + sumsq + "\n" + " watch = " + watch + "\n" + " n = " + n; } public void save(String path) { try { ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(path)); oos.writeObject(this); oos.close(); } catch (Exception e) { System.err.println(e); } } public static StatisticalSummary load(String path) { try { ObjectInputStream ois = new ObjectInputStream( new FileInputStream(path)); StatisticalSummary ss = (StatisticalSummary) ois.readObject(); ois.close(); return ss; } catch (Exception e) { System.err.println(e); return null; } } }