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 */ 017package org.apache.commons.statistics.descriptive; 018 019/** 020 * Computes the arithmetic mean of the available values. Uses the following definition 021 * of the <em>sample mean</em>: 022 * 023 * <p>\[ \frac{1}{n} \sum_{i=1}^n x_i \] 024 * 025 * <p>where \( n \) is the number of samples. 026 * 027 * <ul> 028 * <li>The result is {@code NaN} if no values are added. 029 * </ul> 030 * 031 * <p>This class uses an exact integer sum to compute the mean. 032 * Supports up to 2<sup>63</sup> (exclusive) observations. 033 * This implementation does not check for overflow of the count. 034 * 035 * <p>This class is designed to work with (though does not require) 036 * {@linkplain java.util.stream streams}. 037 * 038 * <p><strong>This implementation is not thread safe.</strong> 039 * If multiple threads access an instance of this class concurrently, 040 * and at least one of the threads invokes the {@link java.util.function.IntConsumer#accept(int) accept} or 041 * {@link StatisticAccumulator#combine(StatisticResult) combine} method, it must be synchronized externally. 042 * 043 * <p>However, it is safe to use {@link java.util.function.IntConsumer#accept(int) accept} 044 * and {@link StatisticAccumulator#combine(StatisticResult) combine} 045 * as {@code accumulator} and {@code combiner} functions of 046 * {@link java.util.stream.Collector Collector} on a parallel stream, 047 * because the parallel implementation of {@link java.util.stream.Stream#collect Stream.collect()} 048 * provides the necessary partitioning, isolation, and merging of results for 049 * safe and efficient parallel execution. 050 * 051 * @see <a href="https://en.wikipedia.org/wiki/Mean">Mean (Wikipedia)</a> 052 * @since 1.1 */ 053public final class IntMean implements IntStatistic, StatisticAccumulator<IntMean> { 054 /** Limit for small sample size where the sum can exactly map to a double. 055 * This is conservatively set using 2^21 values of 2^31 (2^21 ~ 2 million). */ 056 private static final long SMALL_N = 1L << 21; 057 058 /** Sum of the values. */ 059 private final Int128 sum; 060 /** Count of values that have been added. */ 061 private long n; 062 063 /** 064 * Create an instance. 065 */ 066 private IntMean() { 067 this(Int128.create(), 0); 068 } 069 070 /** 071 * Create an instance. 072 * 073 * @param sum Sum of the values. 074 * @param n Count of values that have been added. 075 */ 076 private IntMean(Int128 sum, int n) { 077 this.sum = sum; 078 this.n = n; 079 } 080 081 /** 082 * Creates an instance. 083 * 084 * <p>The initial result is {@code NaN}. 085 * 086 * @return {@code IntMean} instance. 087 */ 088 public static IntMean create() { 089 return new IntMean(); 090 } 091 092 /** 093 * Returns an instance populated using the input {@code values}. 094 * 095 * @param values Values. 096 * @return {@code IntMean} instance. 097 */ 098 public static IntMean of(int... values) { 099 // Sum of an array cannot exceed a 64-bit long 100 long s = 0; 101 for (final int x : values) { 102 s += x; 103 } 104 // Convert 105 return new IntMean(Int128.of(s), values.length); 106 } 107 108 /** 109 * Updates the state of the statistic to reflect the addition of {@code value}. 110 * 111 * @param value Value. 112 */ 113 @Override 114 public void accept(int value) { 115 sum.add(value); 116 n++; 117 } 118 119 /** 120 * Gets the mean of all input values. 121 * 122 * <p>When no values have been added, the result is {@code NaN}. 123 * 124 * @return mean of all values. 125 */ 126 @Override 127 public double getAsDouble() { 128 return computeMean(sum, n); 129 } 130 131 /** 132 * Compute the mean. 133 * 134 * <p>This is a helper method used in higher order moments. 135 * 136 * @param sum Sum of the values. 137 * @param n Count of the values. 138 * @return the mean 139 */ 140 static double computeMean(Int128 sum, long n) { 141 // Fast option when the sum fits within 142 // the mantissa of a double. 143 // Handles n=0 as NaN 144 if (n < SMALL_N) { 145 return (double) sum.lo64() / n; 146 } 147 // Extended precision 148 return IntMath.divide(sum, n); 149 } 150 151 @Override 152 public IntMean combine(IntMean other) { 153 sum.add(other.sum); 154 n += other.n; 155 return this; 156 } 157}