001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.jorphan.math;
020:
021: import java.io.Serializable;
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027:
028: /**
029: * This class serves as a way to calculate the median of a list of values. It is
030: * not threadsafe.
031: */
032: public class StatCalculator implements Serializable {
033: List values = new ArrayList();
034:
035: double sum = 0;
036:
037: double sumOfSquares = 0;
038:
039: double mean = 0;
040:
041: double deviation = 0;
042:
043: int count = 0;
044:
045: long bytes = 0;
046:
047: public void clear() {
048: values.clear();
049: sum = 0;
050: sumOfSquares = 0;
051: mean = 0;
052: deviation = 0;
053: count = 0;
054: }
055:
056: public void addValue(long newValue) {
057: Number val = new Long(newValue);
058: addValue(val);
059: }
060:
061: public void addValue(int newValue) {
062: Number val = new Integer(newValue);
063: addValue(val);
064: }
065:
066: public void addValue(float newValue) {
067: Number val = new Float(newValue);
068: addValue(val);
069: }
070:
071: public void addValue(double newValue) {
072: Number val = new Double(newValue);
073: addValue(val);
074: }
075:
076: public void addBytes(long newValue) {
077: bytes += newValue;
078: }
079:
080: public void addAll(StatCalculator calc) {
081: Iterator iter = calc.values.iterator();
082: while (iter.hasNext()) {
083: addValue((Number) iter.next());
084: }
085: }
086:
087: public Number getMedian() {
088: if (count > 0) {
089: return (Number) values.get((int) (values.size() * .5));
090: }
091: return new Long(0);
092: }
093:
094: public long getTotalBytes() {
095: return bytes;
096: }
097:
098: /**
099: * Get the value which %percent% of the values are less than. This works
100: * just like median (where median represents the 50% point). A typical
101: * desire is to see the 90% point - the value that 90% of the data points
102: * are below, the remaining 10% are above.
103: *
104: * @param percent
105: * @return number of values less than the percentage
106: */
107: public Number getPercentPoint(float percent) {
108: if (count > 0) {
109: return (Number) values.get((int) (values.size() * percent));
110: }
111: return new Long(0);
112: }
113:
114: /**
115: * Get the value which %percent% of the values are less than. This works
116: * just like median (where median represents the 50% point). A typical
117: * desire is to see the 90% point - the value that 90% of the data points
118: * are below, the remaining 10% are above.
119: *
120: * @param percent
121: * @return number of values less than the percentage
122: */
123: public Number getPercentPoint(double percent) {
124: if (count > 0) {
125: return (Number) values.get((int) (values.size() * percent));
126: }
127: return new Long(0);
128: }
129:
130: /**
131: * The method has a limit of 1% as the finest granularity. We do this to
132: * make sure we get a whole number for iterating.
133: *
134: */
135: public synchronized HashMap getDistribution() {
136: HashMap items = new HashMap();
137: Iterator itr = this .values.iterator();
138: Number[] dis;
139: while (itr.hasNext()) {
140: Long nx = (Long) itr.next();
141: if (items.containsKey(nx)) {
142: dis = (Number[]) items.get(nx);
143: dis[1] = new Integer(dis[1].intValue() + 1);
144: items.put(nx, dis);
145: } else {
146: dis = new Number[2];
147: dis[0] = nx;
148: dis[1] = new Integer(1);
149: items.put(nx, dis);
150: }
151: }
152: return items;
153: }
154:
155: public double getMean() {
156: return mean;
157: }
158:
159: public double getStandardDeviation() {
160: return deviation;
161: }
162:
163: public Number getMin() {
164: if (count > 0) {
165: return (Number) values.get(0);
166: }
167: return new Long(Long.MIN_VALUE);
168: }
169:
170: public Number getMax() {
171: if (count > 0) {
172: return (Number) values.get(count - 1);
173: }
174: return new Long(Long.MAX_VALUE);
175: }
176:
177: public int getCount() {
178: return count;
179: }
180:
181: public void addValue(Number val) {
182: addSortedValue(val);
183: count++;
184: double currentVal = val.doubleValue();
185: sum += currentVal;
186: sumOfSquares += currentVal * currentVal;
187: mean = sum / count;
188: deviation = Math.sqrt((sumOfSquares / count) - (mean * mean));
189: }
190:
191: /**
192: * @param val
193: */
194: private void addSortedValue(Number val) {
195: int index = Collections.binarySearch(values, val);
196: if (index >= 0 && index < values.size()) {
197: values.add(index, val);
198: } else if (index == values.size() || values.size() == 0) {
199: values.add(val);
200: } else {
201: values.add((index * (-1)) - 1, val);
202: }
203: }
204: }
|