/** * Copyright 2011 Link Intersystems GmbH <rene.link@link-intersystems.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.link_intersystems.math; import java.math.BigDecimal; import java.math.BigInteger; import com.link_intersystems.lang.Assert; /** * Implementation of an incremental average calculation based on double * precision. Because of the double precision restriction this implementation is * very fast. If you need more precision and high performance is not an issue, * take a look at {@link BigIncrementalAverage}. * * <p> * <h3>Incremental average calculation <br/> * <font size="-1">© * http://jvminside.blogspot.com/2010/01/incremental-average * -calculation.html</font></h3> * <br/> * <cite> <img src="doc-files/average_formula.jpg"/> <br/> * <br/> * Fortunately we can easily transform the formula to an "incremental" form: <br/> * <br/> * <img src="doc-files/incremental_average_formula.jpg"/> * * </cite> <br/> * * * @author RenĂ© Link <a * href="mailto:rene.link@link-intersystems.com">[rene.link@link- * intersystems.com]</a> * @since 1.0.0.0 */ public class IncrementalAverage implements Average<Double> { private long averageValueCount = 0; private Double average = Double.valueOf(0); /** * {@inheritDoc} * * @throws IllegalStateException * if you try to add more than {@link Long#MAX_VALUE} values, * because of data types that are used internally. * @throws IllegalStateException * if value is a {@link BigDecimal} or {@link BigInteger}, * because this implementation can only guarantee double * precision. * @see BigIncrementalAverage * * @since 1.0.0.0 */ public boolean addValue(Number value) { Assert.notNull("value", value); if (value instanceof BigDecimal) { throw new IllegalArgumentException( "value must not be a big decimal, because only double" + " precision can be guranteed by this average implementation."); } if (value instanceof BigInteger) { throw new IllegalArgumentException( "value must not be a big integer, because only double" + " precision can be guranteed by this average implementation."); } if (getAverageValueCount() == Long.MAX_VALUE) { throw new IllegalStateException( "This average implementation can only handle a maximum of " + Long.MAX_VALUE + " values."); } Double oldAverage = average; averageValueCount++; average = average + ((value.doubleValue() - average) / averageValueCount); return oldAverage.compareTo(average) != 0; } /** * {@inheritDoc} * * @since 1.0.0.0 */ public Double getValue() { return average; } /** * * @return the count of values that have been added to this {@link Average}. */ protected long getAverageValueCount() { return averageValueCount; } }