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.math4.legacy.stat.descriptive.summary;
18
19 import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
20 import org.apache.commons.math4.legacy.exception.NullArgumentException;
21 import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic;
22 import org.apache.commons.math4.core.jdkmath.JdkMath;
23 import org.apache.commons.math4.legacy.core.MathArrays;
24
25 /**
26 * Returns the sum of the natural logs for this collection of values.
27 * <p>
28 * Uses {@link org.apache.commons.math4.core.jdkmath.JdkMath#log(double)} to compute the logs.
29 * Therefore,
30 * <ul>
31 * <li>If any of values are < 0, the result is <code>NaN.</code></li>
32 * <li>If all values are non-negative and less than
33 * <code>Double.POSITIVE_INFINITY</code>, but at least one value is 0, the
34 * result is <code>Double.NEGATIVE_INFINITY.</code></li>
35 * <li>If both <code>Double.POSITIVE_INFINITY</code> and
36 * <code>Double.NEGATIVE_INFINITY</code> are among the values, the result is
37 * <code>NaN.</code></li>
38 * </ul>
39 * <p>
40 * <strong>Note that this implementation is not synchronized.</strong> If
41 * multiple threads access an instance of this class concurrently, and at least
42 * one of the threads invokes the <code>increment()</code> or
43 * <code>clear()</code> method, it must be synchronized externally.</p>
44 */
45 public class SumOfLogs extends AbstractStorelessUnivariateStatistic {
46 /** Number of values that have been added. */
47 private int n;
48
49 /**
50 * The currently running value.
51 */
52 private double value;
53
54 /**
55 * Create a SumOfLogs instance.
56 */
57 public SumOfLogs() {
58 value = 0d;
59 n = 0;
60 }
61
62 /**
63 * Copy constructor, creates a new {@code SumOfLogs} identical
64 * to the {@code original}.
65 *
66 * @param original the {@code SumOfLogs} instance to copy
67 * @throws NullArgumentException if original is null
68 */
69 public SumOfLogs(SumOfLogs original) throws NullArgumentException {
70 copy(original, this);
71 }
72
73 /**
74 * {@inheritDoc}
75 */
76 @Override
77 public void increment(final double d) {
78 value += JdkMath.log(d);
79 n++;
80 }
81
82 /**
83 * {@inheritDoc}
84 */
85 @Override
86 public double getResult() {
87 return value;
88 }
89
90 /**
91 * {@inheritDoc}
92 */
93 @Override
94 public long getN() {
95 return n;
96 }
97
98 /**
99 * {@inheritDoc}
100 */
101 @Override
102 public void clear() {
103 value = 0d;
104 n = 0;
105 }
106
107 /**
108 * Returns the sum of the natural logs of the entries in the specified portion of
109 * the input array, or <code>Double.NaN</code> if the designated subarray
110 * is empty.
111 * <p>
112 * Throws <code>MathIllegalArgumentException</code> if the array is null.</p>
113 * <p>
114 * See {@link SumOfLogs}.</p>
115 *
116 * @param values the input array
117 * @param begin index of the first array element to include
118 * @param length the number of elements to include
119 * @return the sum of the natural logs of the values or 0 if
120 * length = 0
121 * @throws MathIllegalArgumentException if the array is null or the array index
122 * parameters are not valid
123 */
124 @Override
125 public double evaluate(final double[] values, final int begin, final int length)
126 throws MathIllegalArgumentException {
127
128 double sumLog = Double.NaN;
129 if (MathArrays.verifyValues(values, begin, length, true)) {
130 sumLog = 0.0;
131 for (int i = begin; i < begin + length; i++) {
132 sumLog += JdkMath.log(values[i]);
133 }
134 }
135 return sumLog;
136 }
137
138 /**
139 * {@inheritDoc}
140 */
141 @Override
142 public SumOfLogs copy() {
143 SumOfLogs result = new SumOfLogs();
144 // No try-catch or advertised exception here because args are valid
145 copy(this, result);
146 return result;
147 }
148
149 /**
150 * Copies source to dest.
151 * <p>Neither source nor dest can be null.</p>
152 *
153 * @param source SumOfLogs to copy
154 * @param dest SumOfLogs to copy to
155 * @throws NullArgumentException if either source or dest is null
156 */
157 public static void copy(SumOfLogs source, SumOfLogs dest)
158 throws NullArgumentException {
159 NullArgumentException.check(source);
160 NullArgumentException.check(dest);
161 dest.n = source.n;
162 dest.value = source.value;
163 }
164 }