001/*
002 * Copyright (C) 2012 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.math;
016
017import static com.google.common.base.Preconditions.checkArgument;
018import static com.google.common.base.Preconditions.checkNotNull;
019import static com.google.common.base.Preconditions.checkState;
020import static com.google.common.math.DoubleUtils.ensureNonNegative;
021import static com.google.common.math.StatsAccumulator.calculateNewMeanNonFinite;
022import static com.google.common.primitives.Doubles.isFinite;
023import static java.lang.Double.NaN;
024import static java.lang.Double.doubleToLongBits;
025import static java.lang.Double.isNaN;
026
027import com.google.common.annotations.GwtIncompatible;
028import com.google.common.annotations.J2ktIncompatible;
029import com.google.common.base.MoreObjects;
030import com.google.common.base.Objects;
031import java.io.Serializable;
032import java.nio.ByteBuffer;
033import java.nio.ByteOrder;
034import java.util.Iterator;
035import java.util.stream.Collector;
036import java.util.stream.DoubleStream;
037import java.util.stream.IntStream;
038import java.util.stream.LongStream;
039import org.jspecify.annotations.Nullable;
040
041/**
042 * A bundle of statistical summary values -- sum, count, mean/average, min and max, and several
043 * forms of variance -- that were computed from a single set of zero or more floating-point values.
044 *
045 * <p>There are two ways to obtain a {@code Stats} instance:
046 *
047 * <ul>
048 *   <li>If all the values you want to summarize are already known, use the appropriate {@code
049 *       Stats.of} factory method below. Primitive arrays, iterables and iterators of any kind of
050 *       {@code Number}, and primitive varargs are supported.
051 *   <li>Or, to avoid storing up all the data first, create a {@link StatsAccumulator} instance,
052 *       feed values to it as you get them, then call {@link StatsAccumulator#snapshot}.
053 * </ul>
054 *
055 * <p>Static convenience methods called {@code meanOf} are also provided for users who wish to
056 * calculate <i>only</i> the mean.
057 *
058 * <p><b>Java 8+ users:</b> If you are not using any of the variance statistics, you may wish to use
059 * built-in JDK libraries instead of this class.
060 *
061 * @author Pete Gillin
062 * @author Kevin Bourrillion
063 * @since 20.0
064 */
065@J2ktIncompatible
066@GwtIncompatible
067public final class Stats implements Serializable {
068
069  private final long count;
070  private final double mean;
071  private final double sumOfSquaresOfDeltas;
072  private final double min;
073  private final double max;
074
075  /**
076   * Internal constructor. Users should use {@link #of} or {@link StatsAccumulator#snapshot}.
077   *
078   * <p>To ensure that the created instance obeys its contract, the parameters should satisfy the
079   * following constraints. This is the callers responsibility and is not enforced here.
080   *
081   * <ul>
082   *   <li>If {@code count} is 0, {@code mean} may have any finite value (its only usage will be to
083   *       get multiplied by 0 to calculate the sum), and the other parameters may have any values
084   *       (they will not be used).
085   *   <li>If {@code count} is 1, {@code sumOfSquaresOfDeltas} must be exactly 0.0 or {@link
086   *       Double#NaN}.
087   * </ul>
088   */
089  Stats(long count, double mean, double sumOfSquaresOfDeltas, double min, double max) {
090    this.count = count;
091    this.mean = mean;
092    this.sumOfSquaresOfDeltas = sumOfSquaresOfDeltas;
093    this.min = min;
094    this.max = max;
095  }
096
097  /**
098   * Returns statistics over a dataset containing the given values.
099   *
100   * @param values a series of values, which will be converted to {@code double} values (this may
101   *     cause loss of precision)
102   */
103  public static Stats of(Iterable<? extends Number> values) {
104    StatsAccumulator accumulator = new StatsAccumulator();
105    accumulator.addAll(values);
106    return accumulator.snapshot();
107  }
108
109  /**
110   * Returns statistics over a dataset containing the given values. The iterator will be completely
111   * consumed by this method.
112   *
113   * @param values a series of values, which will be converted to {@code double} values (this may
114   *     cause loss of precision)
115   */
116  public static Stats of(Iterator<? extends Number> values) {
117    StatsAccumulator accumulator = new StatsAccumulator();
118    accumulator.addAll(values);
119    return accumulator.snapshot();
120  }
121
122  /**
123   * Returns statistics over a dataset containing the given values.
124   *
125   * @param values a series of values
126   */
127  public static Stats of(double... values) {
128    StatsAccumulator accumulator = new StatsAccumulator();
129    accumulator.addAll(values);
130    return accumulator.snapshot();
131  }
132
133  /**
134   * Returns statistics over a dataset containing the given values.
135   *
136   * @param values a series of values
137   */
138  public static Stats of(int... values) {
139    StatsAccumulator accumulator = new StatsAccumulator();
140    accumulator.addAll(values);
141    return accumulator.snapshot();
142  }
143
144  /**
145   * Returns statistics over a dataset containing the given values.
146   *
147   * @param values a series of values, which will be converted to {@code double} values (this may
148   *     cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15))
149   */
150  public static Stats of(long... values) {
151    StatsAccumulator accumulator = new StatsAccumulator();
152    accumulator.addAll(values);
153    return accumulator.snapshot();
154  }
155
156  /**
157   * Returns statistics over a dataset containing the given values. The stream will be completely
158   * consumed by this method.
159   *
160   * <p>If you have a {@code Stream<Double>} rather than a {@code DoubleStream}, you should collect
161   * the values using {@link #toStats()} instead.
162   *
163   * @param values a series of values
164   * @since 28.2 (but only since 33.4.0 in the Android flavor)
165   */
166  public static Stats of(DoubleStream values) {
167    return values
168        .collect(StatsAccumulator::new, StatsAccumulator::add, StatsAccumulator::addAll)
169        .snapshot();
170  }
171
172  /**
173   * Returns statistics over a dataset containing the given values. The stream will be completely
174   * consumed by this method.
175   *
176   * <p>If you have a {@code Stream<Integer>} rather than an {@code IntStream}, you should collect
177   * the values using {@link #toStats()} instead.
178   *
179   * @param values a series of values
180   * @since 28.2 (but only since 33.4.0 in the Android flavor)
181   */
182  public static Stats of(IntStream values) {
183    return values
184        .collect(StatsAccumulator::new, StatsAccumulator::add, StatsAccumulator::addAll)
185        .snapshot();
186  }
187
188  /**
189   * Returns statistics over a dataset containing the given values. The stream will be completely
190   * consumed by this method.
191   *
192   * <p>If you have a {@code Stream<Long>} rather than a {@code LongStream}, you should collect the
193   * values using {@link #toStats()} instead.
194   *
195   * @param values a series of values, which will be converted to {@code double} values (this may
196   *     cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15))
197   * @since 28.2 (but only since 33.4.0 in the Android flavor)
198   */
199  public static Stats of(LongStream values) {
200    return values
201        .collect(StatsAccumulator::new, StatsAccumulator::add, StatsAccumulator::addAll)
202        .snapshot();
203  }
204
205  /**
206   * Returns a {@link Collector} which accumulates statistics from a {@link java.util.stream.Stream}
207   * of any type of boxed {@link Number} into a {@link Stats}. Use by calling {@code
208   * boxedNumericStream.collect(toStats())}. The numbers will be converted to {@code double} values
209   * (which may cause loss of precision).
210   *
211   * <p>If you have any of the primitive streams {@code DoubleStream}, {@code IntStream}, or {@code
212   * LongStream}, you should use the factory method {@link #of} instead.
213   *
214   * @since 28.2 (but only since 33.4.0 in the Android flavor)
215   */
216  public static Collector<Number, StatsAccumulator, Stats> toStats() {
217    return Collector.of(
218        StatsAccumulator::new,
219        (a, x) -> a.add(x.doubleValue()),
220        (l, r) -> {
221          l.addAll(r);
222          return l;
223        },
224        StatsAccumulator::snapshot,
225        Collector.Characteristics.UNORDERED);
226  }
227
228  /** Returns the number of values. */
229  public long count() {
230    return count;
231  }
232
233  /**
234   * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
235   * values. The count must be non-zero.
236   *
237   * <p>If these values are a sample drawn from a population, this is also an unbiased estimator of
238   * the arithmetic mean of the population.
239   *
240   * <h3>Non-finite values</h3>
241   *
242   * <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
243   * contains both {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} then the
244   * result is {@link Double#NaN}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
245   * only or {@link Double#POSITIVE_INFINITY} only, the result is {@link Double#POSITIVE_INFINITY}.
246   * If it contains {@link Double#NEGATIVE_INFINITY} and finite values only or {@link
247   * Double#NEGATIVE_INFINITY} only, the result is {@link Double#NEGATIVE_INFINITY}.
248   *
249   * <p>If you only want to calculate the mean, use {@link #meanOf} instead of creating a {@link
250   * Stats} instance.
251   *
252   * @throws IllegalStateException if the dataset is empty
253   */
254  public double mean() {
255    checkState(count != 0);
256    return mean;
257  }
258
259  /**
260   * Returns the sum of the values.
261   *
262   * <h3>Non-finite values</h3>
263   *
264   * <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
265   * contains both {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} then the
266   * result is {@link Double#NaN}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
267   * only or {@link Double#POSITIVE_INFINITY} only, the result is {@link Double#POSITIVE_INFINITY}.
268   * If it contains {@link Double#NEGATIVE_INFINITY} and finite values only or {@link
269   * Double#NEGATIVE_INFINITY} only, the result is {@link Double#NEGATIVE_INFINITY}.
270   */
271  public double sum() {
272    return mean * count;
273  }
274
275  /**
276   * Returns the <a href="http://en.wikipedia.org/wiki/Variance#Population_variance">population
277   * variance</a> of the values. The count must be non-zero.
278   *
279   * <p>This is guaranteed to return zero if the dataset contains only exactly one finite value. It
280   * is not guaranteed to return zero when the dataset consists of the same value multiple times,
281   * due to numerical errors. However, it is guaranteed never to return a negative result.
282   *
283   * <h3>Non-finite values</h3>
284   *
285   * <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
286   * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
287   *
288   * @throws IllegalStateException if the dataset is empty
289   */
290  public double populationVariance() {
291    checkState(count > 0);
292    if (isNaN(sumOfSquaresOfDeltas)) {
293      return NaN;
294    }
295    if (count == 1) {
296      return 0.0;
297    }
298    return ensureNonNegative(sumOfSquaresOfDeltas) / count();
299  }
300
301  /**
302   * Returns the <a
303   * href="http://en.wikipedia.org/wiki/Standard_deviation#Definition_of_population_values">
304   * population standard deviation</a> of the values. The count must be non-zero.
305   *
306   * <p>This is guaranteed to return zero if the dataset contains only exactly one finite value. It
307   * is not guaranteed to return zero when the dataset consists of the same value multiple times,
308   * due to numerical errors. However, it is guaranteed never to return a negative result.
309   *
310   * <h3>Non-finite values</h3>
311   *
312   * <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
313   * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
314   *
315   * @throws IllegalStateException if the dataset is empty
316   */
317  public double populationStandardDeviation() {
318    return Math.sqrt(populationVariance());
319  }
320
321  /**
322   * Returns the <a href="http://en.wikipedia.org/wiki/Variance#Sample_variance">unbiased sample
323   * variance</a> of the values. If this dataset is a sample drawn from a population, this is an
324   * unbiased estimator of the population variance of the population. The count must be greater than
325   * one.
326   *
327   * <p>This is not guaranteed to return zero when the dataset consists of the same value multiple
328   * times, due to numerical errors. However, it is guaranteed never to return a negative result.
329   *
330   * <h3>Non-finite values</h3>
331   *
332   * <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
333   * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
334   *
335   * @throws IllegalStateException if the dataset is empty or contains a single value
336   */
337  public double sampleVariance() {
338    checkState(count > 1);
339    if (isNaN(sumOfSquaresOfDeltas)) {
340      return NaN;
341    }
342    return ensureNonNegative(sumOfSquaresOfDeltas) / (count - 1);
343  }
344
345  /**
346   * Returns the <a
347   * href="http://en.wikipedia.org/wiki/Standard_deviation#Corrected_sample_standard_deviation">
348   * corrected sample standard deviation</a> of the values. If this dataset is a sample drawn from a
349   * population, this is an estimator of the population standard deviation of the population which
350   * is less biased than {@link #populationStandardDeviation()} (the unbiased estimator depends on
351   * the distribution). The count must be greater than one.
352   *
353   * <p>This is not guaranteed to return zero when the dataset consists of the same value multiple
354   * times, due to numerical errors. However, it is guaranteed never to return a negative result.
355   *
356   * <h3>Non-finite values</h3>
357   *
358   * <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
359   * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
360   *
361   * @throws IllegalStateException if the dataset is empty or contains a single value
362   */
363  public double sampleStandardDeviation() {
364    return Math.sqrt(sampleVariance());
365  }
366
367  /**
368   * Returns the lowest value in the dataset. The count must be non-zero.
369   *
370   * <h3>Non-finite values</h3>
371   *
372   * <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
373   * contains {@link Double#NEGATIVE_INFINITY} and not {@link Double#NaN} then the result is {@link
374   * Double#NEGATIVE_INFINITY}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
375   * only then the result is the lowest finite value. If it contains {@link
376   * Double#POSITIVE_INFINITY} only then the result is {@link Double#POSITIVE_INFINITY}.
377   *
378   * @throws IllegalStateException if the dataset is empty
379   */
380  public double min() {
381    checkState(count != 0);
382    return min;
383  }
384
385  /**
386   * Returns the highest value in the dataset. The count must be non-zero.
387   *
388   * <h3>Non-finite values</h3>
389   *
390   * <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
391   * contains {@link Double#POSITIVE_INFINITY} and not {@link Double#NaN} then the result is {@link
392   * Double#POSITIVE_INFINITY}. If it contains {@link Double#NEGATIVE_INFINITY} and finite values
393   * only then the result is the highest finite value. If it contains {@link
394   * Double#NEGATIVE_INFINITY} only then the result is {@link Double#NEGATIVE_INFINITY}.
395   *
396   * @throws IllegalStateException if the dataset is empty
397   */
398  public double max() {
399    checkState(count != 0);
400    return max;
401  }
402
403  /**
404   * {@inheritDoc}
405   *
406   * <p><b>Note:</b> This tests exact equality of the calculated statistics, including the floating
407   * point values. Two instances are guaranteed to be considered equal if one is copied from the
408   * other using {@code second = new StatsAccumulator().addAll(first).snapshot()}, if both were
409   * obtained by calling {@code snapshot()} on the same {@link StatsAccumulator} without adding any
410   * values in between the two calls, or if one is obtained from the other after round-tripping
411   * through java serialization. However, floating point rounding errors mean that it may be false
412   * for some instances where the statistics are mathematically equal, including instances
413   * constructed from the same values in a different order... or (in the general case) even in the
414   * same order. (It is guaranteed to return true for instances constructed from the same values in
415   * the same order if {@code strictfp} is in effect, or if the system architecture guarantees
416   * {@code strictfp}-like semantics.)
417   */
418  @Override
419  public boolean equals(@Nullable Object obj) {
420    if (obj == null) {
421      return false;
422    }
423    if (getClass() != obj.getClass()) {
424      return false;
425    }
426    Stats other = (Stats) obj;
427    return count == other.count
428        && doubleToLongBits(mean) == doubleToLongBits(other.mean)
429        && doubleToLongBits(sumOfSquaresOfDeltas) == doubleToLongBits(other.sumOfSquaresOfDeltas)
430        && doubleToLongBits(min) == doubleToLongBits(other.min)
431        && doubleToLongBits(max) == doubleToLongBits(other.max);
432  }
433
434  /**
435   * {@inheritDoc}
436   *
437   * <p><b>Note:</b> This hash code is consistent with exact equality of the calculated statistics,
438   * including the floating point values. See the note on {@link #equals} for details.
439   */
440  @Override
441  public int hashCode() {
442    return Objects.hashCode(count, mean, sumOfSquaresOfDeltas, min, max);
443  }
444
445  @Override
446  public String toString() {
447    if (count() > 0) {
448      return MoreObjects.toStringHelper(this)
449          .add("count", count)
450          .add("mean", mean)
451          .add("populationStandardDeviation", populationStandardDeviation())
452          .add("min", min)
453          .add("max", max)
454          .toString();
455    } else {
456      return MoreObjects.toStringHelper(this).add("count", count).toString();
457    }
458  }
459
460  double sumOfSquaresOfDeltas() {
461    return sumOfSquaresOfDeltas;
462  }
463
464  /**
465   * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
466   * values. The count must be non-zero.
467   *
468   * <p>The definition of the mean is the same as {@link Stats#mean}.
469   *
470   * @param values a series of values, which will be converted to {@code double} values (this may
471   *     cause loss of precision)
472   * @throws IllegalArgumentException if the dataset is empty
473   */
474  public static double meanOf(Iterable<? extends Number> values) {
475    return meanOf(values.iterator());
476  }
477
478  /**
479   * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
480   * values. The count must be non-zero.
481   *
482   * <p>The definition of the mean is the same as {@link Stats#mean}.
483   *
484   * @param values a series of values, which will be converted to {@code double} values (this may
485   *     cause loss of precision)
486   * @throws IllegalArgumentException if the dataset is empty
487   */
488  public static double meanOf(Iterator<? extends Number> values) {
489    checkArgument(values.hasNext());
490    long count = 1;
491    double mean = values.next().doubleValue();
492    while (values.hasNext()) {
493      double value = values.next().doubleValue();
494      count++;
495      if (isFinite(value) && isFinite(mean)) {
496        // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
497        mean += (value - mean) / count;
498      } else {
499        mean = calculateNewMeanNonFinite(mean, value);
500      }
501    }
502    return mean;
503  }
504
505  /**
506   * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
507   * values. The count must be non-zero.
508   *
509   * <p>The definition of the mean is the same as {@link Stats#mean}.
510   *
511   * @param values a series of values
512   * @throws IllegalArgumentException if the dataset is empty
513   */
514  public static double meanOf(double... values) {
515    checkArgument(values.length > 0);
516    double mean = values[0];
517    for (int index = 1; index < values.length; index++) {
518      double value = values[index];
519      if (isFinite(value) && isFinite(mean)) {
520        // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
521        mean += (value - mean) / (index + 1);
522      } else {
523        mean = calculateNewMeanNonFinite(mean, value);
524      }
525    }
526    return mean;
527  }
528
529  /**
530   * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
531   * values. The count must be non-zero.
532   *
533   * <p>The definition of the mean is the same as {@link Stats#mean}.
534   *
535   * @param values a series of values
536   * @throws IllegalArgumentException if the dataset is empty
537   */
538  public static double meanOf(int... values) {
539    checkArgument(values.length > 0);
540    double mean = values[0];
541    for (int index = 1; index < values.length; index++) {
542      double value = values[index];
543      if (isFinite(value) && isFinite(mean)) {
544        // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
545        mean += (value - mean) / (index + 1);
546      } else {
547        mean = calculateNewMeanNonFinite(mean, value);
548      }
549    }
550    return mean;
551  }
552
553  /**
554   * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the
555   * values. The count must be non-zero.
556   *
557   * <p>The definition of the mean is the same as {@link Stats#mean}.
558   *
559   * @param values a series of values, which will be converted to {@code double} values (this may
560   *     cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15))
561   * @throws IllegalArgumentException if the dataset is empty
562   */
563  public static double meanOf(long... values) {
564    checkArgument(values.length > 0);
565    double mean = values[0];
566    for (int index = 1; index < values.length; index++) {
567      double value = values[index];
568      if (isFinite(value) && isFinite(mean)) {
569        // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
570        mean += (value - mean) / (index + 1);
571      } else {
572        mean = calculateNewMeanNonFinite(mean, value);
573      }
574    }
575    return mean;
576  }
577
578  // Serialization helpers
579
580  /** The size of byte array representation in bytes. */
581  static final int BYTES = (Long.SIZE + Double.SIZE * 4) / Byte.SIZE;
582
583  /**
584   * Gets a byte array representation of this instance.
585   *
586   * <p><b>Note:</b> No guarantees are made regarding stability of the representation between
587   * versions.
588   */
589  public byte[] toByteArray() {
590    ByteBuffer buff = ByteBuffer.allocate(BYTES).order(ByteOrder.LITTLE_ENDIAN);
591    writeTo(buff);
592    return buff.array();
593  }
594
595  /**
596   * Writes to the given {@link ByteBuffer} a byte representation of this instance.
597   *
598   * <p><b>Note:</b> No guarantees are made regarding stability of the representation between
599   * versions.
600   *
601   * @param buffer A {@link ByteBuffer} with at least BYTES {@link ByteBuffer#remaining}, ordered as
602   *     {@link ByteOrder#LITTLE_ENDIAN}, to which a BYTES-long byte representation of this instance
603   *     is written. In the process increases the position of {@link ByteBuffer} by BYTES.
604   */
605  void writeTo(ByteBuffer buffer) {
606    checkNotNull(buffer);
607    checkArgument(
608        buffer.remaining() >= BYTES,
609        "Expected at least Stats.BYTES = %s remaining , got %s",
610        BYTES,
611        buffer.remaining());
612    buffer
613        .putLong(count)
614        .putDouble(mean)
615        .putDouble(sumOfSquaresOfDeltas)
616        .putDouble(min)
617        .putDouble(max);
618  }
619
620  /**
621   * Creates a Stats instance from the given byte representation which was obtained by {@link
622   * #toByteArray}.
623   *
624   * <p><b>Note:</b> No guarantees are made regarding stability of the representation between
625   * versions.
626   */
627  public static Stats fromByteArray(byte[] byteArray) {
628    checkNotNull(byteArray);
629    checkArgument(
630        byteArray.length == BYTES,
631        "Expected Stats.BYTES = %s remaining , got %s",
632        BYTES,
633        byteArray.length);
634    return readFrom(ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN));
635  }
636
637  /**
638   * Creates a Stats instance from the byte representation read from the given {@link ByteBuffer}.
639   *
640   * <p><b>Note:</b> No guarantees are made regarding stability of the representation between
641   * versions.
642   *
643   * @param buffer A {@link ByteBuffer} with at least BYTES {@link ByteBuffer#remaining}, ordered as
644   *     {@link ByteOrder#LITTLE_ENDIAN}, from which a BYTES-long byte representation of this
645   *     instance is read. In the process increases the position of {@link ByteBuffer} by BYTES.
646   */
647  static Stats readFrom(ByteBuffer buffer) {
648    checkNotNull(buffer);
649    checkArgument(
650        buffer.remaining() >= BYTES,
651        "Expected at least Stats.BYTES = %s remaining , got %s",
652        BYTES,
653        buffer.remaining());
654    return new Stats(
655        buffer.getLong(),
656        buffer.getDouble(),
657        buffer.getDouble(),
658        buffer.getDouble(),
659        buffer.getDouble());
660  }
661
662  private static final long serialVersionUID = 0;
663}