/*
* Copyright (C) 2012 The Guava Authors
*
* 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.google.common.math;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.math.DoubleUtils.ensureNonNegative;
import static com.google.common.math.StatsAccumulator.calculateNewMeanNonFinite;
import static com.google.common.primitives.Doubles.isFinite;
import static java.lang.Double.NaN;
import static java.lang.Double.doubleToLongBits;
import static java.lang.Double.isNaN;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Iterator;
import org.checkerframework.checker.nullness.qual.Nullable;
A bundle of statistical summary values -- sum, count, mean/average, min and max, and several
forms of variance -- that were computed from a single set of zero or more floating-point values.
There are two ways to obtain a Stats
instance:
- If all the values you want to summarize are already known, use the appropriate
Stats.of
factory method below. Primitive arrays, iterables and iterators of any kind of Number
, and primitive varargs are supported. - Or, to avoid storing up all the data first, create a
StatsAccumulator
instance, feed values to it as you get them, then call StatsAccumulator.snapshot
.
Static convenience methods called meanOf
are also provided for users who wish to calculate only the mean.
Java 8 users: If you are not using any of the variance statistics, you may wish to use
built-in JDK libraries instead of this class.
Author: Pete Gillin, Kevin Bourrillion Since: 20.0
/**
* A bundle of statistical summary values -- sum, count, mean/average, min and max, and several
* forms of variance -- that were computed from a single set of zero or more floating-point values.
*
* <p>There are two ways to obtain a {@code Stats} instance:
*
* <ul>
* <li>If all the values you want to summarize are already known, use the appropriate {@code
* Stats.of} factory method below. Primitive arrays, iterables and iterators of any kind of
* {@code Number}, and primitive varargs are supported.
* <li>Or, to avoid storing up all the data first, create a {@link StatsAccumulator} instance,
* feed values to it as you get them, then call {@link StatsAccumulator#snapshot}.
* </ul>
*
* <p>Static convenience methods called {@code meanOf} are also provided for users who wish to
* calculate <i>only</i> the mean.
*
* <p><b>Java 8 users:</b> If you are not using any of the variance statistics, you may wish to use
* built-in JDK libraries instead of this class.
*
* @author Pete Gillin
* @author Kevin Bourrillion
* @since 20.0
*/
@Beta
@GwtIncompatible
public final class Stats implements Serializable {
private final long count;
private final double mean;
private final double sumOfSquaresOfDeltas;
private final double min;
private final double max;
Internal constructor. Users should use of
or StatsAccumulator.snapshot
. To ensure that the created instance obeys its contract, the parameters should satisfy the
following constraints. This is the callers responsibility and is not enforced here.
- If
count
is 0, mean
may have any finite value (its only usage will be to get multiplied by 0 to calculate the sum), and the other parameters may have any values (they will not be used). - If
count
is 1, sumOfSquaresOfDeltas
must be exactly 0.0 or Double.NaN
.
/**
* Internal constructor. Users should use {@link #of} or {@link StatsAccumulator#snapshot}.
*
* <p>To ensure that the created instance obeys its contract, the parameters should satisfy the
* following constraints. This is the callers responsibility and is not enforced here.
*
* <ul>
* <li>If {@code count} is 0, {@code mean} may have any finite value (its only usage will be to
* get multiplied by 0 to calculate the sum), and the other parameters may have any values
* (they will not be used).
* <li>If {@code count} is 1, {@code sumOfSquaresOfDeltas} must be exactly 0.0 or {@link
* Double#NaN}.
* </ul>
*/
Stats(long count, double mean, double sumOfSquaresOfDeltas, double min, double max) {
this.count = count;
this.mean = mean;
this.sumOfSquaresOfDeltas = sumOfSquaresOfDeltas;
this.min = min;
this.max = max;
}
Returns statistics over a dataset containing the given values.
Params: - values – a series of values, which will be converted to
double
values (this may cause loss of precision)
/**
* Returns statistics over a dataset containing the given values.
*
* @param values a series of values, which will be converted to {@code double} values (this may
* cause loss of precision)
*/
public static Stats of(Iterable<? extends Number> values) {
StatsAccumulator accumulator = new StatsAccumulator();
accumulator.addAll(values);
return accumulator.snapshot();
}
Returns statistics over a dataset containing the given values.
Params: - values – a series of values, which will be converted to
double
values (this may cause loss of precision)
/**
* Returns statistics over a dataset containing the given values.
*
* @param values a series of values, which will be converted to {@code double} values (this may
* cause loss of precision)
*/
public static Stats of(Iterator<? extends Number> values) {
StatsAccumulator accumulator = new StatsAccumulator();
accumulator.addAll(values);
return accumulator.snapshot();
}
Returns statistics over a dataset containing the given values.
Params: - values – a series of values
/**
* Returns statistics over a dataset containing the given values.
*
* @param values a series of values
*/
public static Stats of(double... values) {
StatsAccumulator acummulator = new StatsAccumulator();
acummulator.addAll(values);
return acummulator.snapshot();
}
Returns statistics over a dataset containing the given values.
Params: - values – a series of values
/**
* Returns statistics over a dataset containing the given values.
*
* @param values a series of values
*/
public static Stats of(int... values) {
StatsAccumulator acummulator = new StatsAccumulator();
acummulator.addAll(values);
return acummulator.snapshot();
}
Returns statistics over a dataset containing the given values.
Params: - values – a series of values, which will be converted to
double
values (this may cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15))
/**
* Returns statistics over a dataset containing the given values.
*
* @param values a series of values, which will be converted to {@code double} values (this may
* cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15))
*/
public static Stats of(long... values) {
StatsAccumulator acummulator = new StatsAccumulator();
acummulator.addAll(values);
return acummulator.snapshot();
}
Returns the number of values. /** Returns the number of values. */
public long count() {
return count;
}
Returns the arithmetic mean of the
values. The count must be non-zero.
If these values are a sample drawn from a population, this is also an unbiased estimator of
the arithmetic mean of the population.
Non-finite values
If the dataset contains Double.NaN
then the result is Double.NaN
. If it contains both Double.POSITIVE_INFINITY
and Double.NEGATIVE_INFINITY
then the result is Double.NaN
. If it contains Double.POSITIVE_INFINITY
and finite values only or Double.POSITIVE_INFINITY
only, the result is Double.POSITIVE_INFINITY
. If it contains Double.NEGATIVE_INFINITY
and finite values only or Double.NEGATIVE_INFINITY
only, the result is Double.NEGATIVE_INFINITY
.
If you only want to calculate the mean, use {#meanOf} instead of creating a Stats
instance.
Throws: - IllegalStateException – if the dataset is empty
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
* values. The count must be non-zero.
*
* <p>If these values are a sample drawn from a population, this is also an unbiased estimator of
* the arithmetic mean of the population.
*
* <h3>Non-finite values</h3>
*
* <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
* contains both {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} then the
* result is {@link Double#NaN}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
* only or {@link Double#POSITIVE_INFINITY} only, the result is {@link Double#POSITIVE_INFINITY}.
* If it contains {@link Double#NEGATIVE_INFINITY} and finite values only or {@link
* Double#NEGATIVE_INFINITY} only, the result is {@link Double#NEGATIVE_INFINITY}.
*
* <p>If you only want to calculate the mean, use {#meanOf} instead of creating a {@link Stats}
* instance.
*
* @throws IllegalStateException if the dataset is empty
*/
public double mean() {
checkState(count != 0);
return mean;
}
Returns the sum of the values.
Non-finite values
If the dataset contains Double.NaN
then the result is Double.NaN
. If it contains both Double.POSITIVE_INFINITY
and Double.NEGATIVE_INFINITY
then the result is Double.NaN
. If it contains Double.POSITIVE_INFINITY
and finite values only or Double.POSITIVE_INFINITY
only, the result is Double.POSITIVE_INFINITY
. If it contains Double.NEGATIVE_INFINITY
and finite values only or Double.NEGATIVE_INFINITY
only, the result is Double.NEGATIVE_INFINITY
.
/**
* Returns the sum of the values.
*
* <h3>Non-finite values</h3>
*
* <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
* contains both {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} then the
* result is {@link Double#NaN}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
* only or {@link Double#POSITIVE_INFINITY} only, the result is {@link Double#POSITIVE_INFINITY}.
* If it contains {@link Double#NEGATIVE_INFINITY} and finite values only or {@link
* Double#NEGATIVE_INFINITY} only, the result is {@link Double#NEGATIVE_INFINITY}.
*/
public double sum() {
return mean * count;
}
Returns the population
variance of the values. The count must be non-zero.
This is guaranteed to return zero if the dataset contains only exactly one finite value. It
is not guaranteed to return zero when the dataset consists of the same value multiple times,
due to numerical errors. However, it is guaranteed never to return a negative result.
Non-finite values
If the dataset contains any non-finite values (Double.POSITIVE_INFINITY
, Double.NEGATIVE_INFINITY
, or Double.NaN
) then the result is Double.NaN
.
Throws: - IllegalStateException – if the dataset is empty
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Variance#Population_variance">population
* variance</a> of the values. The count must be non-zero.
*
* <p>This is guaranteed to return zero if the dataset contains only exactly one finite value. It
* is not guaranteed to return zero when the dataset consists of the same value multiple times,
* due to numerical errors. However, it is guaranteed never to return a negative result.
*
* <h3>Non-finite values</h3>
*
* <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
* Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
*
* @throws IllegalStateException if the dataset is empty
*/
public double populationVariance() {
checkState(count > 0);
if (isNaN(sumOfSquaresOfDeltas)) {
return NaN;
}
if (count == 1) {
return 0.0;
}
return ensureNonNegative(sumOfSquaresOfDeltas) / count();
}
Returns the
population standard deviation of the values. The count must be non-zero.
This is guaranteed to return zero if the dataset contains only exactly one finite value. It
is not guaranteed to return zero when the dataset consists of the same value multiple times,
due to numerical errors. However, it is guaranteed never to return a negative result.
Non-finite values
If the dataset contains any non-finite values (Double.POSITIVE_INFINITY
, Double.NEGATIVE_INFINITY
, or Double.NaN
) then the result is Double.NaN
.
Throws: - IllegalStateException – if the dataset is empty
/**
* Returns the <a
* href="http://en.wikipedia.org/wiki/Standard_deviation#Definition_of_population_values">
* population standard deviation</a> of the values. The count must be non-zero.
*
* <p>This is guaranteed to return zero if the dataset contains only exactly one finite value. It
* is not guaranteed to return zero when the dataset consists of the same value multiple times,
* due to numerical errors. However, it is guaranteed never to return a negative result.
*
* <h3>Non-finite values</h3>
*
* <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
* Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
*
* @throws IllegalStateException if the dataset is empty
*/
public double populationStandardDeviation() {
return Math.sqrt(populationVariance());
}
Returns the unbiased sample
variance of the values. If this dataset is a sample drawn from a population, this is an
unbiased estimator of the population variance of the population. The count must be greater than
one.
This is not guaranteed to return zero when the dataset consists of the same value multiple
times, due to numerical errors. However, it is guaranteed never to return a negative result.
Non-finite values
If the dataset contains any non-finite values (Double.POSITIVE_INFINITY
, Double.NEGATIVE_INFINITY
, or Double.NaN
) then the result is Double.NaN
.
Throws: - IllegalStateException – if the dataset is empty or contains a single value
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Variance#Sample_variance">unbiased sample
* variance</a> of the values. If this dataset is a sample drawn from a population, this is an
* unbiased estimator of the population variance of the population. The count must be greater than
* one.
*
* <p>This is not guaranteed to return zero when the dataset consists of the same value multiple
* times, due to numerical errors. However, it is guaranteed never to return a negative result.
*
* <h3>Non-finite values</h3>
*
* <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
* Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
*
* @throws IllegalStateException if the dataset is empty or contains a single value
*/
public double sampleVariance() {
checkState(count > 1);
if (isNaN(sumOfSquaresOfDeltas)) {
return NaN;
}
return ensureNonNegative(sumOfSquaresOfDeltas) / (count - 1);
}
Returns the
corrected sample standard deviation of the values. If this dataset is a sample drawn from a population, this is an estimator of the population standard deviation of the population which is less biased than populationStandardDeviation()
(the unbiased estimator depends on the distribution). The count must be greater than one. This is not guaranteed to return zero when the dataset consists of the same value multiple
times, due to numerical errors. However, it is guaranteed never to return a negative result.
Non-finite values
If the dataset contains any non-finite values (Double.POSITIVE_INFINITY
, Double.NEGATIVE_INFINITY
, or Double.NaN
) then the result is Double.NaN
.
Throws: - IllegalStateException – if the dataset is empty or contains a single value
/**
* Returns the <a
* href="http://en.wikipedia.org/wiki/Standard_deviation#Corrected_sample_standard_deviation">
* corrected sample standard deviation</a> of the values. If this dataset is a sample drawn from a
* population, this is an estimator of the population standard deviation of the population which
* is less biased than {@link #populationStandardDeviation()} (the unbiased estimator depends on
* the distribution). The count must be greater than one.
*
* <p>This is not guaranteed to return zero when the dataset consists of the same value multiple
* times, due to numerical errors. However, it is guaranteed never to return a negative result.
*
* <h3>Non-finite values</h3>
*
* <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
* Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
*
* @throws IllegalStateException if the dataset is empty or contains a single value
*/
public double sampleStandardDeviation() {
return Math.sqrt(sampleVariance());
}
Returns the lowest value in the dataset. The count must be non-zero.
Non-finite values
If the dataset contains Double.NaN
then the result is Double.NaN
. If it contains Double.NEGATIVE_INFINITY
and not Double.NaN
then the result is Double.NEGATIVE_INFINITY
. If it contains Double.POSITIVE_INFINITY
and finite values only then the result is the lowest finite value. If it contains Double.POSITIVE_INFINITY
only then the result is Double.POSITIVE_INFINITY
.
Throws: - IllegalStateException – if the dataset is empty
/**
* Returns the lowest value in the dataset. The count must be non-zero.
*
* <h3>Non-finite values</h3>
*
* <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
* contains {@link Double#NEGATIVE_INFINITY} and not {@link Double#NaN} then the result is {@link
* Double#NEGATIVE_INFINITY}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
* only then the result is the lowest finite value. If it contains {@link
* Double#POSITIVE_INFINITY} only then the result is {@link Double#POSITIVE_INFINITY}.
*
* @throws IllegalStateException if the dataset is empty
*/
public double min() {
checkState(count != 0);
return min;
}
Returns the highest value in the dataset. The count must be non-zero.
Non-finite values
If the dataset contains Double.NaN
then the result is Double.NaN
. If it contains Double.POSITIVE_INFINITY
and not Double.NaN
then the result is Double.POSITIVE_INFINITY
. If it contains Double.NEGATIVE_INFINITY
and finite values only then the result is the highest finite value. If it contains Double.NEGATIVE_INFINITY
only then the result is Double.NEGATIVE_INFINITY
.
Throws: - IllegalStateException – if the dataset is empty
/**
* Returns the highest value in the dataset. The count must be non-zero.
*
* <h3>Non-finite values</h3>
*
* <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
* contains {@link Double#POSITIVE_INFINITY} and not {@link Double#NaN} then the result is {@link
* Double#POSITIVE_INFINITY}. If it contains {@link Double#NEGATIVE_INFINITY} and finite values
* only then the result is the highest finite value. If it contains {@link
* Double#NEGATIVE_INFINITY} only then the result is {@link Double#NEGATIVE_INFINITY}.
*
* @throws IllegalStateException if the dataset is empty
*/
public double max() {
checkState(count != 0);
return max;
}
{@inheritDoc}
Note: This tests exact equality of the calculated statistics, including the floating point values. Two instances are guaranteed to be considered equal if one is copied from the other using second = new StatsAccumulator().addAll(first).snapshot()
, if both were obtained by calling snapshot()
on the same StatsAccumulator
without adding any values in between the two calls, or if one is obtained from the other after round-tripping through java serialization. However, floating point rounding errors mean that it may be false for some instances where the statistics are mathematically equal, including instances constructed from the same values in a different order... or (in the general case) even in the same order. (It is guaranteed to return true for instances constructed from the same values in the same order if strictfp
is in effect, or if the system architecture guarantees strictfp
-like semantics.)
/**
* {@inheritDoc}
*
* <p><b>Note:</b> This tests exact equality of the calculated statistics, including the floating
* point values. Two instances are guaranteed to be considered equal if one is copied from the
* other using {@code second = new StatsAccumulator().addAll(first).snapshot()}, if both were
* obtained by calling {@code snapshot()} on the same {@link StatsAccumulator} without adding any
* values in between the two calls, or if one is obtained from the other after round-tripping
* through java serialization. However, floating point rounding errors mean that it may be false
* for some instances where the statistics are mathematically equal, including instances
* constructed from the same values in a different order... or (in the general case) even in the
* same order. (It is guaranteed to return true for instances constructed from the same values in
* the same order if {@code strictfp} is in effect, or if the system architecture guarantees
* {@code strictfp}-like semantics.)
*/
@Override
public boolean equals(@Nullable Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Stats other = (Stats) obj;
return (count == other.count)
&& (doubleToLongBits(mean) == doubleToLongBits(other.mean))
&& (doubleToLongBits(sumOfSquaresOfDeltas) == doubleToLongBits(other.sumOfSquaresOfDeltas))
&& (doubleToLongBits(min) == doubleToLongBits(other.min))
&& (doubleToLongBits(max) == doubleToLongBits(other.max));
}
{@inheritDoc}
Note: This hash code is consistent with exact equality of the calculated statistics, including the floating point values. See the note on equals
for details.
/**
* {@inheritDoc}
*
* <p><b>Note:</b> This hash code is consistent with exact equality of the calculated statistics,
* including the floating point values. See the note on {@link #equals} for details.
*/
@Override
public int hashCode() {
return Objects.hashCode(count, mean, sumOfSquaresOfDeltas, min, max);
}
@Override
public String toString() {
if (count() > 0) {
return MoreObjects.toStringHelper(this)
.add("count", count)
.add("mean", mean)
.add("populationStandardDeviation", populationStandardDeviation())
.add("min", min)
.add("max", max)
.toString();
} else {
return MoreObjects.toStringHelper(this).add("count", count).toString();
}
}
double sumOfSquaresOfDeltas() {
return sumOfSquaresOfDeltas;
}
Returns the arithmetic mean of the
values. The count must be non-zero.
The definition of the mean is the same as mean
.
Params: - values – a series of values, which will be converted to
double
values (this may cause loss of precision)
Throws: - IllegalArgumentException – if the dataset is empty
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
* values. The count must be non-zero.
*
* <p>The definition of the mean is the same as {@link Stats#mean}.
*
* @param values a series of values, which will be converted to {@code double} values (this may
* cause loss of precision)
* @throws IllegalArgumentException if the dataset is empty
*/
public static double meanOf(Iterable<? extends Number> values) {
return meanOf(values.iterator());
}
Returns the arithmetic mean of the
values. The count must be non-zero.
The definition of the mean is the same as mean
.
Params: - values – a series of values, which will be converted to
double
values (this may cause loss of precision)
Throws: - IllegalArgumentException – if the dataset is empty
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
* values. The count must be non-zero.
*
* <p>The definition of the mean is the same as {@link Stats#mean}.
*
* @param values a series of values, which will be converted to {@code double} values (this may
* cause loss of precision)
* @throws IllegalArgumentException if the dataset is empty
*/
public static double meanOf(Iterator<? extends Number> values) {
checkArgument(values.hasNext());
long count = 1;
double mean = values.next().doubleValue();
while (values.hasNext()) {
double value = values.next().doubleValue();
count++;
if (isFinite(value) && isFinite(mean)) {
// Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
mean += (value - mean) / count;
} else {
mean = calculateNewMeanNonFinite(mean, value);
}
}
return mean;
}
Returns the arithmetic mean of the
values. The count must be non-zero.
The definition of the mean is the same as mean
.
Params: - values – a series of values
Throws: - IllegalArgumentException – if the dataset is empty
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
* values. The count must be non-zero.
*
* <p>The definition of the mean is the same as {@link Stats#mean}.
*
* @param values a series of values
* @throws IllegalArgumentException if the dataset is empty
*/
public static double meanOf(double... values) {
checkArgument(values.length > 0);
double mean = values[0];
for (int index = 1; index < values.length; index++) {
double value = values[index];
if (isFinite(value) && isFinite(mean)) {
// Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
mean += (value - mean) / (index + 1);
} else {
mean = calculateNewMeanNonFinite(mean, value);
}
}
return mean;
}
Returns the arithmetic mean of the
values. The count must be non-zero.
The definition of the mean is the same as mean
.
Params: - values – a series of values
Throws: - IllegalArgumentException – if the dataset is empty
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
* values. The count must be non-zero.
*
* <p>The definition of the mean is the same as {@link Stats#mean}.
*
* @param values a series of values
* @throws IllegalArgumentException if the dataset is empty
*/
public static double meanOf(int... values) {
checkArgument(values.length > 0);
double mean = values[0];
for (int index = 1; index < values.length; index++) {
double value = values[index];
if (isFinite(value) && isFinite(mean)) {
// Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
mean += (value - mean) / (index + 1);
} else {
mean = calculateNewMeanNonFinite(mean, value);
}
}
return mean;
}
Returns the arithmetic mean of the
values. The count must be non-zero.
The definition of the mean is the same as mean
.
Params: - values – a series of values, which will be converted to
double
values (this may cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15))
Throws: - IllegalArgumentException – if the dataset is empty
/**
* Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
* values. The count must be non-zero.
*
* <p>The definition of the mean is the same as {@link Stats#mean}.
*
* @param values a series of values, which will be converted to {@code double} values (this may
* cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15))
* @throws IllegalArgumentException if the dataset is empty
*/
public static double meanOf(long... values) {
checkArgument(values.length > 0);
double mean = values[0];
for (int index = 1; index < values.length; index++) {
double value = values[index];
if (isFinite(value) && isFinite(mean)) {
// Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
mean += (value - mean) / (index + 1);
} else {
mean = calculateNewMeanNonFinite(mean, value);
}
}
return mean;
}
// Serialization helpers
The size of byte array representation in bytes. /** The size of byte array representation in bytes. */
static final int BYTES = (Long.SIZE + Double.SIZE * 4) / Byte.SIZE;
Gets a byte array representation of this instance.
Note: No guarantees are made regarding stability of the representation between
versions.
/**
* Gets a byte array representation of this instance.
*
* <p><b>Note:</b> No guarantees are made regarding stability of the representation between
* versions.
*/
public byte[] toByteArray() {
ByteBuffer buff = ByteBuffer.allocate(BYTES).order(ByteOrder.LITTLE_ENDIAN);
writeTo(buff);
return buff.array();
}
Writes to the given ByteBuffer
a byte representation of this instance. Note: No guarantees are made regarding stability of the representation between
versions.
Params: - buffer – A
ByteBuffer
with at least BYTES Buffer.remaining
, ordered as ByteOrder.LITTLE_ENDIAN
, to which a BYTES-long byte representation of this instance is written. In the process increases the position of ByteBuffer
by BYTES.
/**
* Writes to the given {@link ByteBuffer} a byte representation of this instance.
*
* <p><b>Note:</b> No guarantees are made regarding stability of the representation between
* versions.
*
* @param buffer A {@link ByteBuffer} with at least BYTES {@link ByteBuffer#remaining}, ordered as
* {@link ByteOrder#LITTLE_ENDIAN}, to which a BYTES-long byte representation of this instance
* is written. In the process increases the position of {@link ByteBuffer} by BYTES.
*/
void writeTo(ByteBuffer buffer) {
checkNotNull(buffer);
checkArgument(
buffer.remaining() >= BYTES,
"Expected at least Stats.BYTES = %s remaining , got %s",
BYTES,
buffer.remaining());
buffer
.putLong(count)
.putDouble(mean)
.putDouble(sumOfSquaresOfDeltas)
.putDouble(min)
.putDouble(max);
}
Creates a Stats instance from the given byte representation which was obtained by toByteArray
. Note: No guarantees are made regarding stability of the representation between
versions.
/**
* Creates a Stats instance from the given byte representation which was obtained by {@link
* #toByteArray}.
*
* <p><b>Note:</b> No guarantees are made regarding stability of the representation between
* versions.
*/
public static Stats fromByteArray(byte[] byteArray) {
checkNotNull(byteArray);
checkArgument(
byteArray.length == BYTES,
"Expected Stats.BYTES = %s remaining , got %s",
BYTES,
byteArray.length);
return readFrom(ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN));
}
Creates a Stats instance from the byte representation read from the given ByteBuffer
. Note: No guarantees are made regarding stability of the representation between
versions.
Params: - buffer – A
ByteBuffer
with at least BYTES Buffer.remaining
, ordered as ByteOrder.LITTLE_ENDIAN
, from which a BYTES-long byte representation of this instance is read. In the process increases the position of ByteBuffer
by BYTES.
/**
* Creates a Stats instance from the byte representation read from the given {@link ByteBuffer}.
*
* <p><b>Note:</b> No guarantees are made regarding stability of the representation between
* versions.
*
* @param buffer A {@link ByteBuffer} with at least BYTES {@link ByteBuffer#remaining}, ordered as
* {@link ByteOrder#LITTLE_ENDIAN}, from which a BYTES-long byte representation of this
* instance is read. In the process increases the position of {@link ByteBuffer} by BYTES.
*/
static Stats readFrom(ByteBuffer buffer) {
checkNotNull(buffer);
checkArgument(
buffer.remaining() >= BYTES,
"Expected at least Stats.BYTES = %s remaining , got %s",
BYTES,
buffer.remaining());
return new Stats(
buffer.getLong(),
buffer.getDouble(),
buffer.getDouble(),
buffer.getDouble(),
buffer.getDouble());
}
private static final long serialVersionUID = 0;
}