1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.statistics.descriptive; 18 19 /** 20 * Returns the sum of the {@link Math#log(double) natural logarithm} of available values. 21 * 22 * <ul> 23 * <li>The result is zero if no values are added. 24 * <li>The result is {@code NaN} if any of the values is {@code NaN}. 25 * <li>The result is {@code NaN} if any of the values is negative. 26 * </ul> 27 * 28 * <p>The sum follows the IEEE754 result for summing infinite values: 29 * 30 * <ul> 31 * <li>The result is {@code +infinity} if all values are in the range {@code (0, +infinity]} 32 * and at least one value is {@code +infinity}. 33 * <li>The result is {@code -infinity} if all values are in the range {@code [0, +infinity)} 34 * and at least one value is zero. 35 * <li>The result is {@code NaN} if all values are in the range {@code [0, +infinity]} 36 * and at least one value is zero, and one value is {@code +infinity}. 37 * </ul> 38 * 39 * <p>This class is designed to work with (though does not require) 40 * {@linkplain java.util.stream streams}. 41 * 42 * <p><strong>This instance is not thread safe.</strong> 43 * If multiple threads access an instance of this class concurrently, 44 * and at least one of the threads invokes the {@link java.util.function.DoubleConsumer#accept(double) accept} or 45 * {@link StatisticAccumulator#combine(StatisticResult) combine} method, it must be synchronized externally. 46 * 47 * <p>However, it is safe to use {@link java.util.function.DoubleConsumer#accept(double) accept} 48 * and {@link StatisticAccumulator#combine(StatisticResult) combine} 49 * as {@code accumulator} and {@code combiner} functions of 50 * {@link java.util.stream.Collector Collector} on a parallel stream, 51 * because the parallel instance of {@link java.util.stream.Stream#collect Stream.collect()} 52 * provides the necessary partitioning, isolation, and merging of results for 53 * safe and efficient parallel execution. 54 * 55 * @see org.apache.commons.numbers.core.Sum 56 * @see Math#log(double) 57 * @since 1.1 58 */ 59 public final class SumOfLogs implements DoubleStatistic, StatisticAccumulator<SumOfLogs> { 60 61 /** {@link org.apache.commons.numbers.core.Sum Sum} used to compute the sum. */ 62 private final org.apache.commons.numbers.core.Sum delegate = 63 org.apache.commons.numbers.core.Sum.create(); 64 65 /** 66 * Create an instance. 67 */ 68 private SumOfLogs() { 69 // No-op 70 } 71 72 /** 73 * Creates an instance. 74 * 75 * <p>The initial result is zero. 76 * 77 * @return {@code SumOfLogs} instance. 78 */ 79 public static SumOfLogs create() { 80 return new SumOfLogs(); 81 } 82 83 /** 84 * Returns an instance populated using the input {@code values}. 85 * 86 * <p>The result is {@code NaN} if any of the values is {@code NaN} 87 * or negative; or the sum at any point is a {@code NaN}. 88 * 89 * <p>When the input is an empty array, the result is zero. 90 * 91 * @param values Values. 92 * @return {@code SumOfLogs} instance. 93 */ 94 public static SumOfLogs of(double... values) { 95 return Statistics.add(new SumOfLogs(), values); 96 } 97 98 /** 99 * Returns an instance populated using the specified range of {@code values}. 100 * 101 * <p>The result is {@code NaN} if any of the values is {@code NaN} 102 * or negative; or the sum at any point is a {@code NaN}. 103 * 104 * <p>When the range is empty, the result is zero. 105 * 106 * @param values Values. 107 * @param from Inclusive start of the range. 108 * @param to Exclusive end of the range. 109 * @return {@code SumOfLogs} instance. 110 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 111 * @since 1.2 112 */ 113 public static SumOfLogs ofRange(double[] values, int from, int to) { 114 Statistics.checkFromToIndex(from, to, values.length); 115 return createFromRange(values, from, to); 116 } 117 118 /** 119 * Create an instance using the specified range of {@code values}. 120 * 121 * <p>Warning: No range checks are performed. 122 * 123 * @param values Values. 124 * @param from Inclusive start of the range. 125 * @param to Exclusive end of the range. 126 * @return {@code SumOfLogs} instance. 127 */ 128 static SumOfLogs createFromRange(double[] values, int from, int to) { 129 return Statistics.add(new SumOfLogs(), values, from, to); 130 } 131 132 /** 133 * Returns an instance populated using the input {@code values}. 134 * 135 * <p>The result is {@code NaN} if any of the values is negative. 136 * 137 * <p>When the input is an empty array, the result is zero. 138 * 139 * @param values Values. 140 * @return {@code SumOfLogs} instance. 141 */ 142 public static SumOfLogs of(int... values) { 143 return Statistics.add(new SumOfLogs(), values); 144 } 145 146 /** 147 * Returns an instance populated using the specified range of {@code values}. 148 * 149 * <p>The result is {@code NaN} if any of the values is negative. 150 * 151 * <p>When the range is empty, the result is zero. 152 * 153 * @param values Values. 154 * @param from Inclusive start of the range. 155 * @param to Exclusive end of the range. 156 * @return {@code SumOfLogs} instance. 157 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 158 * @since 1.2 159 */ 160 public static SumOfLogs ofRange(int[] values, int from, int to) { 161 Statistics.checkFromToIndex(from, to, values.length); 162 return createFromRange(values, from, to); 163 } 164 165 /** 166 * Create an instance using the specified range of {@code values}. 167 * 168 * <p>Warning: No range checks are performed. 169 * 170 * @param values Values. 171 * @param from Inclusive start of the range. 172 * @param to Exclusive end of the range. 173 * @return {@code SumOfLogs} instance. 174 */ 175 static SumOfLogs createFromRange(int[] values, int from, int to) { 176 return Statistics.add(new SumOfLogs(), values, from, to); 177 } 178 179 /** 180 * Returns an instance populated using the input {@code values}. 181 * 182 * <p>The result is {@code NaN} if any of the values is negative. 183 * 184 * <p>When the input is an empty array, the result is zero. 185 * 186 * @param values Values. 187 * @return {@code SumOfLogs} instance. 188 */ 189 public static SumOfLogs of(long... values) { 190 return Statistics.add(new SumOfLogs(), values); 191 } 192 193 /** 194 * Returns an instance populated using the specified range of {@code values}. 195 * 196 * <p>The result is {@code NaN} if any of the values is negative. 197 * 198 * <p>When the range is empty, the result is zero. 199 * 200 * @param values Values. 201 * @param from Inclusive start of the range. 202 * @param to Exclusive end of the range. 203 * @return {@code SumOfLogs} instance. 204 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 205 * @since 1.2 206 */ 207 public static SumOfLogs ofRange(long[] values, int from, int to) { 208 Statistics.checkFromToIndex(from, to, values.length); 209 return createFromRange(values, from, to); 210 } 211 212 /** 213 * Create an instance using the specified range of {@code values}. 214 * 215 * <p>Warning: No range checks are performed. 216 * 217 * @param values Values. 218 * @param from Inclusive start of the range. 219 * @param to Exclusive end of the range. 220 * @return {@code SumOfLogs} instance. 221 */ 222 static SumOfLogs createFromRange(long[] values, int from, int to) { 223 return Statistics.add(new SumOfLogs(), values, from, to); 224 } 225 226 /** 227 * Updates the state of the statistic to reflect the addition of {@code value}. 228 * 229 * @param value Value. 230 */ 231 @Override 232 public void accept(double value) { 233 delegate.accept(Math.log(value)); 234 } 235 236 /** 237 * Gets the sum of all input values. 238 * 239 * <p>When no values have been added, the result is zero. 240 * 241 * @return sum of all values. 242 */ 243 @Override 244 public double getAsDouble() { 245 return delegate.getAsDouble(); 246 } 247 248 @Override 249 public SumOfLogs combine(SumOfLogs other) { 250 delegate.add(other.delegate); 251 return this; 252 } 253 }