package freenet.support.math; import java.util.ArrayList; /** * A RunningAverage that tracks both the median and mean of a series of values. * WARNING: Uses memory and proportional to the number of reports! Only for debugging! * (Also uses CPU time O(N log N) with the number of reports in currentValue()). * @author Matthew Toseland <toad@amphibian.dyndns.org> (0xE43DA450) */ public final class MedianMeanRunningAverage implements RunningAverage, Cloneable { private static final long serialVersionUID = 1L; final ArrayList<Double> reports; final TrivialRunningAverage mean; /** * */ public MedianMeanRunningAverage() { reports = new ArrayList<Double>(); mean = new TrivialRunningAverage(); } /** * * @param average */ public MedianMeanRunningAverage(MedianMeanRunningAverage average) { this.mean = new TrivialRunningAverage(average.mean); this.reports = new ArrayList<Double>(); reports.addAll(average.reports); } @Override public MedianMeanRunningAverage clone() { // Override clone() for synchronization. // Implement Cloneable to shut up findbugs. synchronized (this) { return new MedianMeanRunningAverage(this); } } @Override public synchronized long countReports() { return reports.size(); } /** * * @return */ @Override public synchronized double currentValue() { int size = reports.size(); int middle = size / 2; java.util.Collections.sort(reports); return reports.get(middle); } /** * * @param d */ @Override public synchronized void report(double d) { mean.report(d); reports.add(d); } /** * * @param d */ @Override public void report(long d) { report((double)d); } @Override public double valueIfReported(double r) { throw new UnsupportedOperationException(); } @Override public synchronized String toString() { return "Median "+currentValue()+" mean "+mean.currentValue(); } /** * * @return */ public synchronized double meanValue() { return mean.currentValue(); } }