001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2004-2007 Robert Grimm
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public License
007: * version 2.1 as published by the Free Software Foundation.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.util;
020:
021: import java.util.ArrayList;
022: import java.util.Collections;
023: import java.util.List;
024:
025: /**
026: * Implementation of a simple statistics collector.
027: *
028: * @author Robert Grimm
029: * @version $Revision: 1.13 $
030: */
031: public class Statistics {
032:
033: /** The list of numbers. */
034: private List<Double> numbers;
035:
036: /** Create a new statistics collector. */
037: public Statistics() {
038: numbers = new ArrayList<Double>();
039: }
040:
041: /** Reset this statistics collector. */
042: public void reset() {
043: numbers.clear();
044: }
045:
046: /**
047: * Add the specified number.
048: *
049: * @param d The number.
050: */
051: public void add(final double d) {
052: numbers.add(d);
053: }
054:
055: /**
056: * Get the size of this collection.
057: *
058: * @return The size.
059: */
060: public int size() {
061: return numbers.size();
062: }
063:
064: /**
065: * Get the specified number.
066: *
067: * @param idx The index.
068: * @return The corresponding number.
069: * @throws IndexOutOfBoundsException
070: * Signals that the index is out of range.
071: */
072: public double get(final int idx) {
073: return numbers.get(idx);
074: }
075:
076: /**
077: * Calculate the sum.
078: *
079: * @return The sum.
080: */
081: public double sum() {
082: double sum = 0;
083:
084: final int size = numbers.size();
085: for (int i = 0; i < size; i++) {
086: sum += numbers.get(i);
087: }
088:
089: return sum;
090: }
091:
092: /**
093: * Calculate the mean.
094: *
095: * @return The mean.
096: */
097: public double mean() {
098: double mean = 0;
099:
100: final int size = numbers.size();
101: for (int i = 0; i < size; i++) {
102: mean += (numbers.get(i) - mean) / (i + 1);
103: }
104:
105: return mean;
106: }
107:
108: /**
109: * Calculate the median. Note that this method does not change the
110: * order of numbers in this collection, i.e. it sorts a copy.
111: *
112: * @return The median.
113: */
114: public double median() {
115: if (0 == size()) {
116: return 0;
117:
118: } else {
119: List<Double> sorted = new ArrayList<Double>(numbers);
120: Collections.sort(sorted);
121: return sorted.get(size() / 2);
122: }
123: }
124:
125: /**
126: * Calculate the standard deviation.
127: *
128: * @return The standard deviation.
129: */
130: public double stdev() {
131: final double mean = mean();
132: double variance = 0;
133:
134: final int size = size();
135: for (int i = 0; i < size; i++) {
136: final double diff = numbers.get(i) - mean;
137: variance += (diff * diff - variance) / (i + 1);
138: }
139:
140: return Math.sqrt(variance);
141: }
142:
143: /**
144: * Round the specified number to two digits after the decimal point.
145: *
146: * @param d The number.
147: * @return The rounded number.
148: */
149: public static double round(final double d) {
150: return (Math.floor((d * 100) + 0.5) / 100);
151: }
152:
153: /**
154: * Compute the least squares fit. This method computes the least
155: * squares fit to a straight line model without a constant term for
156: * the specified collections of numbers: <code>y = mx</code>.
157: *
158: * @param x The collection of x coordinates.
159: * @param y The collection of y coordiantes.
160: * @return The slope of the corresponding line model.
161: * @throws IllegalArgumentException Signals that the two collections
162: * are empty or not of the same size.
163: */
164: public static double fitSlope(Statistics x, Statistics y) {
165: if (x.size() != y.size()) {
166: throw new IllegalArgumentException(
167: "Inconsistent collection sizes");
168: } else if (0 == x.size()) {
169: throw new IllegalArgumentException("Empty collections");
170: }
171:
172: double xMean = 0;
173: double yMean = 0;
174: double dx2Mean = 0;
175: double dxdyMean = 0;
176: final int size = x.size();
177:
178: for (int i = 0; i < size; i++) {
179: xMean += (x.get(i) - xMean) / (i + 1);
180: yMean += (y.get(i) - yMean) / (i + 1);
181: }
182:
183: for (int i = 0; i < size; i++) {
184: final double dx = x.get(i) - xMean;
185: final double dy = y.get(i) - yMean;
186:
187: dx2Mean += (dx * dx - dx2Mean) / (i + 1);
188: dxdyMean += (dx * dy - dxdyMean) / (i + 1);
189: }
190:
191: return (xMean * yMean + dxdyMean) / (xMean * xMean + dx2Mean);
192: }
193:
194: }
|