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 * Returns an instance populated using the specified range of {@code values}. 110 * 111 * @param values Values. 112 * @param from Inclusive start of the range. 113 * @param to Exclusive end of the range. 114 * @return {@code IntMean} instance. 115 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 116 * @since 1.2 117 */ 118 public static IntMean ofRange(int[] values, int from, int to) { 119 Statistics.checkFromToIndex(from, to, values.length); 120 return createFromRange(values, from, to); 121 } 122 123 /** 124 * Create an instance using the specified range of {@code values}. 125 * 126 * <p>Warning: No range checks are performed. 127 * 128 * @param values Values. 129 * @param from Inclusive start of the range. 130 * @param to Exclusive end of the range. 131 * @return {@code IntMean} instance. 132 */ 133 static IntMean createFromRange(int[] values, int from, int to) { 134 // Sum of an array cannot exceed a 64-bit long 135 long s = 0; 136 for (int i = from; i < to; i++) { 137 s += values[i]; 138 } 139 // Convert 140 return new IntMean(Int128.of(s), to - from); 141 } 142 143 /** 144 * Updates the state of the statistic to reflect the addition of {@code value}. 145 * 146 * @param value Value. 147 */ 148 @Override 149 public void accept(int value) { 150 sum.add(value); 151 n++; 152 } 153 154 /** 155 * Gets the mean of all input values. 156 * 157 * <p>When no values have been added, the result is {@code NaN}. 158 * 159 * @return mean of all values. 160 */ 161 @Override 162 public double getAsDouble() { 163 return computeMean(sum, n); 164 } 165 166 /** 167 * Compute the mean. 168 * 169 * <p>This is a helper method used in higher order moments. 170 * 171 * @param sum Sum of the values. 172 * @param n Count of the values. 173 * @return the mean 174 */ 175 static double computeMean(Int128 sum, long n) { 176 // Fast option when the sum fits within 177 // the mantissa of a double. 178 // Handles n=0 as NaN 179 if (n < SMALL_N) { 180 return (double) sum.lo64() / n; 181 } 182 // Extended precision 183 return sum.divideToDouble(n); 184 } 185 186 @Override 187 public IntMean combine(IntMean other) { 188 sum.add(other.sum); 189 n += other.n; 190 return this; 191 } 192}