GeometricMean.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.commons.math4.legacy.stat.descriptive.moment;
- import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
- import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
- import org.apache.commons.math4.legacy.exception.NullArgumentException;
- import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
- import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic;
- import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatistic;
- import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs;
- import org.apache.commons.math4.core.jdkmath.JdkMath;
- /**
- * Returns the <a href="http://www.xycoon.com/geometric_mean.htm">
- * geometric mean </a> of the available values.
- * <p>
- * Uses a {@link SumOfLogs} instance to compute sum of logs and returns
- * <code> exp( 1/n (sum of logs) ).</code> Therefore, </p>
- * <ul>
- * <li>If any of values are {@code < 0}, the result is <code>NaN.</code></li>
- * <li>If all values are non-negative and less than
- * <code>Double.POSITIVE_INFINITY</code>, but at least one value is 0, the
- * result is <code>0.</code></li>
- * <li>If both <code>Double.POSITIVE_INFINITY</code> and
- * <code>Double.NEGATIVE_INFINITY</code> are among the values, the result is
- * <code>NaN.</code></li>
- * </ul>
- * <p>
- * <strong>Note that this implementation is not synchronized.</strong> If
- * multiple threads access an instance of this class concurrently, and at least
- * one of the threads invokes the <code>increment()</code> or
- * <code>clear()</code> method, it must be synchronized externally.</p>
- */
- public class GeometricMean extends AbstractStorelessUnivariateStatistic {
- /** Wrapped SumOfLogs instance. */
- private StorelessUnivariateStatistic sumOfLogs;
- /**
- * Create a GeometricMean instance.
- */
- public GeometricMean() {
- sumOfLogs = new SumOfLogs();
- }
- /**
- * Copy constructor, creates a new {@code GeometricMean} identical
- * to the {@code original}.
- *
- * @param original the {@code GeometricMean} instance to copy
- * @throws NullArgumentException if original is null
- */
- public GeometricMean(GeometricMean original) throws NullArgumentException {
- super();
- copy(original, this);
- }
- /**
- * Create a GeometricMean instance using the given SumOfLogs instance.
- * @param sumOfLogs sum of logs instance to use for computation.
- */
- public GeometricMean(SumOfLogs sumOfLogs) {
- this.sumOfLogs = sumOfLogs;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public GeometricMean copy() {
- GeometricMean result = new GeometricMean();
- // no try-catch or advertised exception because args guaranteed non-null
- copy(this, result);
- return result;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void increment(final double d) {
- sumOfLogs.increment(d);
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public double getResult() {
- if (sumOfLogs.getN() > 0) {
- return JdkMath.exp(sumOfLogs.getResult() / sumOfLogs.getN());
- } else {
- return Double.NaN;
- }
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void clear() {
- sumOfLogs.clear();
- }
- /**
- * Returns the geometric mean of the entries in the specified portion
- * of the input array.
- * <p>
- * See {@link GeometricMean} for details on the computing algorithm.</p>
- * <p>
- * Throws <code>IllegalArgumentException</code> if the array is null.</p>
- *
- * @param values input array containing the values
- * @param begin first array element to include
- * @param length the number of elements to include
- * @return the geometric mean or Double.NaN if length = 0 or
- * any of the values are <= 0.
- * @throws MathIllegalArgumentException if the input array is null or the array
- * index parameters are not valid
- */
- @Override
- public double evaluate(final double[] values, final int begin, final int length)
- throws MathIllegalArgumentException {
- return JdkMath.exp(sumOfLogs.evaluate(values, begin, length) / length);
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public long getN() {
- return sumOfLogs.getN();
- }
- /**
- * <p>Sets the implementation for the sum of logs.</p>
- * <p>This method must be activated before any data has been added - i.e.,
- * before {@link #increment(double) increment} has been used to add data;
- * otherwise an IllegalStateException will be thrown.</p>
- *
- * @param sumLogImpl the StorelessUnivariateStatistic instance to use
- * for computing the log sum
- * @throws MathIllegalStateException if data has already been added
- * (i.e if n > 0)
- */
- public void setSumLogImpl(StorelessUnivariateStatistic sumLogImpl)
- throws MathIllegalStateException {
- checkEmpty();
- this.sumOfLogs = sumLogImpl;
- }
- /**
- * Returns the currently configured sum of logs implementation.
- *
- * @return the StorelessUnivariateStatistic implementing the log sum
- */
- public StorelessUnivariateStatistic getSumLogImpl() {
- return sumOfLogs;
- }
- /**
- * Copies source to dest.
- * <p>Neither source nor dest can be null.</p>
- *
- * @param source GeometricMean to copy
- * @param dest GeometricMean to copy to
- * @throws NullArgumentException if either source or dest is null
- */
- public static void copy(GeometricMean source, GeometricMean dest)
- throws NullArgumentException {
- NullArgumentException.check(source);
- NullArgumentException.check(dest);
- dest.sumOfLogs = source.sumOfLogs.copy();
- }
- /**
- * Throws MathIllegalStateException if n > 0.
- * @throws MathIllegalStateException if data has been added to this statistic
- */
- private void checkEmpty() throws MathIllegalStateException {
- if (getN() > 0) {
- throw new MathIllegalStateException(
- LocalizedFormats.VALUES_ADDED_BEFORE_CONFIGURING_STATISTIC,
- getN());
- }
- }
- }