MATH-689
Moved array utilities from "MathUtils" to "MathArrays". git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1182147 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d64c7a3bfb
commit
d092e09531
|
@ -273,7 +273,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se
|
|||
* weights are to be treated as "expansion values," as will be the case if for example
|
||||
* the weights represent frequency counts. To normalize weights so that the denominator
|
||||
* in the variance computation equals the length of the input vector minus one, use <pre>
|
||||
* <code>evaluate(values, MathUtils.normalizeArray(weights, values.length)); </code>
|
||||
* <code>evaluate(values, MathArrays.normalizeArray(weights, values.length)); </code>
|
||||
* </pre>
|
||||
* <p>
|
||||
* Returns 0 for a single-value (i.e. length = 1) sample.</p>
|
||||
|
@ -332,7 +332,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se
|
|||
* weights are to be treated as "expansion values," as will be the case if for example
|
||||
* the weights represent frequency counts. To normalize weights so that the denominator
|
||||
* in the variance computation equals the length of the input vector minus one, use <pre>
|
||||
* <code>evaluate(values, MathUtils.normalizeArray(weights, values.length)); </code>
|
||||
* <code>evaluate(values, MathArrays.normalizeArray(weights, values.length)); </code>
|
||||
* </pre>
|
||||
* <p>
|
||||
* Returns 0 for a single-value (i.e. length = 1) sample.</p>
|
||||
|
@ -462,7 +462,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se
|
|||
* weights are to be treated as "expansion values," as will be the case if for example
|
||||
* the weights represent frequency counts. To normalize weights so that the denominator
|
||||
* in the variance computation equals the length of the input vector minus one, use <pre>
|
||||
* <code>evaluate(values, MathUtils.normalizeArray(weights, values.length), mean); </code>
|
||||
* <code>evaluate(values, MathArrays.normalizeArray(weights, values.length), mean); </code>
|
||||
* </pre>
|
||||
* <p>
|
||||
* Returns 0 for a single-value (i.e. length = 1) sample.</p>
|
||||
|
@ -539,7 +539,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se
|
|||
* weights are to be treated as "expansion values," as will be the case if for example
|
||||
* the weights represent frequency counts. To normalize weights so that the denominator
|
||||
* in the variance computation equals the length of the input vector minus one, use <pre>
|
||||
* <code>evaluate(values, MathUtils.normalizeArray(weights, values.length), mean); </code>
|
||||
* <code>evaluate(values, MathArrays.normalizeArray(weights, values.length), mean); </code>
|
||||
* </pre>
|
||||
* <p>
|
||||
* Returns 0 for a single-value (i.e. length = 1) sample.</p>
|
||||
|
|
|
@ -26,6 +26,9 @@ import org.apache.commons.math.exception.DimensionMismatchException;
|
|||
import org.apache.commons.math.exception.MathInternalError;
|
||||
import org.apache.commons.math.exception.NonMonotonicSequenceException;
|
||||
import org.apache.commons.math.exception.NullArgumentException;
|
||||
import org.apache.commons.math.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math.exception.util.LocalizedFormats;
|
||||
import org.apache.commons.math.exception.MathArithmeticException;
|
||||
|
||||
/**
|
||||
* Arrays utilities.
|
||||
|
@ -1024,4 +1027,57 @@ public class MathArrays {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes an array to make it sum to a specified value.
|
||||
* Returns the result of the transformation <pre>
|
||||
* x |-> x * normalizedSum / sum
|
||||
* </pre>
|
||||
* applied to each non-NaN element x of the input array, where sum is the
|
||||
* sum of the non-NaN entries in the input array.</p>
|
||||
*
|
||||
* <p>Throws IllegalArgumentException if {@code normalizedSum} is infinite
|
||||
* or NaN and ArithmeticException if the input array contains any infinite elements
|
||||
* or sums to 0.</p>
|
||||
*
|
||||
* <p>Ignores (i.e., copies unchanged to the output array) NaNs in the input array.</p>
|
||||
*
|
||||
* @param values Input array to be normalized
|
||||
* @param normalizedSum Target sum for the normalized array
|
||||
* @return the normalized array.
|
||||
* @throws MathArithmeticException if the input array contains infinite
|
||||
* elements or sums to zero.
|
||||
* @throws MathIllegalArgumentException if the target sum is infinite or {@code NaN}.
|
||||
* @since 2.1
|
||||
*/
|
||||
public static double[] normalizeArray(double[] values, double normalizedSum) {
|
||||
if (Double.isInfinite(normalizedSum)) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_INFINITE);
|
||||
}
|
||||
if (Double.isNaN(normalizedSum)) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_NAN);
|
||||
}
|
||||
double sum = 0d;
|
||||
final int len = values.length;
|
||||
double[] out = new double[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (Double.isInfinite(values[i])) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.INFINITE_ARRAY_ELEMENT, values[i], i);
|
||||
}
|
||||
if (!Double.isNaN(values[i])) {
|
||||
sum += values[i];
|
||||
}
|
||||
}
|
||||
if (sum == 0) {
|
||||
throw new MathArithmeticException(LocalizedFormats.ARRAY_SUMS_TO_ZERO);
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (Double.isNaN(values[i])) {
|
||||
out[i] = Double.NaN;
|
||||
} else {
|
||||
out[i] = values[i] * normalizedSum / sum;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -936,58 +936,6 @@ public final class MathUtils {
|
|||
return a - p * FastMath.floor((a - offset) / p) - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Normalizes an array to make it sum to a specified value.
|
||||
* Returns the result of the transformation <pre>
|
||||
* x |-> x * normalizedSum / sum
|
||||
* </pre>
|
||||
* applied to each non-NaN element x of the input array, where sum is the
|
||||
* sum of the non-NaN entries in the input array.</p>
|
||||
*
|
||||
* <p>Throws IllegalArgumentException if {@code normalizedSum} is infinite
|
||||
* or NaN and ArithmeticException if the input array contains any infinite elements
|
||||
* or sums to 0</p>
|
||||
*
|
||||
* <p>Ignores (i.e., copies unchanged to the output array) NaNs in the input array.</p>
|
||||
*
|
||||
* @param values input array to be normalized
|
||||
* @param normalizedSum target sum for the normalized array
|
||||
* @return normalized array
|
||||
* @throws MathArithmeticException if the input array contains infinite elements or sums to zero
|
||||
* @throws MathIllegalArgumentException if the target sum is infinite or NaN
|
||||
* @since 2.1
|
||||
*/
|
||||
public static double[] normalizeArray(double[] values, double normalizedSum) {
|
||||
if (Double.isInfinite(normalizedSum)) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_INFINITE);
|
||||
}
|
||||
if (Double.isNaN(normalizedSum)) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_NAN);
|
||||
}
|
||||
double sum = 0d;
|
||||
final int len = values.length;
|
||||
double[] out = new double[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (Double.isInfinite(values[i])) {
|
||||
throw new MathIllegalArgumentException(LocalizedFormats.INFINITE_ARRAY_ELEMENT, values[i], i);
|
||||
}
|
||||
if (!Double.isNaN(values[i])) {
|
||||
sum += values[i];
|
||||
}
|
||||
}
|
||||
if (sum == 0) {
|
||||
throw new MathArithmeticException(LocalizedFormats.ARRAY_SUMS_TO_ZERO);
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (Double.isNaN(values[i])) {
|
||||
out[i] = Double.NaN;
|
||||
} else {
|
||||
out[i] = values[i] * normalizedSum / sum;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the given value to the specified number of decimal places. The
|
||||
* value is rounded using the {@link BigDecimal#ROUND_HALF_UP} method.
|
||||
|
|
|
@ -18,7 +18,7 @@ package org.apache.commons.math.stat.descriptive.moment;
|
|||
|
||||
import org.apache.commons.math.stat.descriptive.StorelessUnivariateStatisticAbstractTest;
|
||||
import org.apache.commons.math.stat.descriptive.UnivariateStatistic;
|
||||
import org.apache.commons.math.util.MathUtils;
|
||||
import org.apache.commons.math.util.MathArrays;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -110,7 +110,7 @@ public class VarianceTest extends StorelessUnivariateStatisticAbstractTest{
|
|||
// All weights the same -> when weights are normalized to sum to the length of the values array,
|
||||
// weighted variance = unweighted value
|
||||
Assert.assertEquals(expectedValue(),
|
||||
variance.evaluate(testArray, MathUtils.normalizeArray(identicalWeightsArray, testArray.length),
|
||||
variance.evaluate(testArray, MathArrays.normalizeArray(identicalWeightsArray, testArray.length),
|
||||
0, testArray.length), getTolerance());
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,10 @@ import java.util.Arrays;
|
|||
import org.apache.commons.math.exception.NonMonotonicSequenceException;
|
||||
import org.apache.commons.math.exception.DimensionMismatchException;
|
||||
import org.apache.commons.math.exception.NullArgumentException;
|
||||
import org.apache.commons.math.exception.MathArithmeticException;
|
||||
import org.apache.commons.math.exception.MathIllegalArgumentException;
|
||||
import org.apache.commons.math.random.Well1024a;
|
||||
import org.apache.commons.math.TestUtils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -586,4 +589,49 @@ public class MathArraysTest {
|
|||
Assert.assertFalse(MathArrays.equalsIncludingNaN(new double[] { 1d },
|
||||
new double[] { FastMath.nextAfter(FastMath.nextAfter(1d, 2d), 2d) }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeArray() {
|
||||
double[] testValues1 = new double[] {1, 1, 2};
|
||||
TestUtils.assertEquals( new double[] {.25, .25, .5},
|
||||
MathArrays.normalizeArray(testValues1, 1),
|
||||
Double.MIN_VALUE);
|
||||
|
||||
double[] testValues2 = new double[] {-1, -1, 1};
|
||||
TestUtils.assertEquals( new double[] {1, 1, -1},
|
||||
MathArrays.normalizeArray(testValues2, 1),
|
||||
Double.MIN_VALUE);
|
||||
|
||||
// Ignore NaNs
|
||||
double[] testValues3 = new double[] {-1, -1, Double.NaN, 1, Double.NaN};
|
||||
TestUtils.assertEquals( new double[] {1, 1,Double.NaN, -1, Double.NaN},
|
||||
MathArrays.normalizeArray(testValues3, 1),
|
||||
Double.MIN_VALUE);
|
||||
|
||||
// Zero sum -> MathArithmeticException
|
||||
double[] zeroSum = new double[] {-1, 1};
|
||||
try {
|
||||
MathArrays.normalizeArray(zeroSum, 1);
|
||||
Assert.fail("expecting MathArithmeticException");
|
||||
} catch (MathArithmeticException ex) {}
|
||||
|
||||
// Infinite elements -> MathArithmeticException
|
||||
double[] hasInf = new double[] {1, 2, 1, Double.NEGATIVE_INFINITY};
|
||||
try {
|
||||
MathArrays.normalizeArray(hasInf, 1);
|
||||
Assert.fail("expecting MathIllegalArgumentException");
|
||||
} catch (MathIllegalArgumentException ex) {}
|
||||
|
||||
// Infinite target -> MathIllegalArgumentException
|
||||
try {
|
||||
MathArrays.normalizeArray(testValues1, Double.POSITIVE_INFINITY);
|
||||
Assert.fail("expecting MathIllegalArgumentException");
|
||||
} catch (MathIllegalArgumentException ex) {}
|
||||
|
||||
// NaN target -> MathIllegalArgumentException
|
||||
try {
|
||||
MathArrays.normalizeArray(testValues1, Double.NaN);
|
||||
Assert.fail("expecting MathIllegalArgumentException");
|
||||
} catch (MathIllegalArgumentException ex) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -842,55 +842,6 @@ public final class MathUtilsTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeArray() {
|
||||
double[] testValues1 = new double[] {1, 1, 2};
|
||||
TestUtils.assertEquals(
|
||||
new double[] {.25, .25, .5},
|
||||
MathUtils.normalizeArray(testValues1, 1),
|
||||
Double.MIN_VALUE);
|
||||
|
||||
double[] testValues2 = new double[] {-1, -1, 1};
|
||||
TestUtils.assertEquals(
|
||||
new double[] {1, 1, -1},
|
||||
MathUtils.normalizeArray(testValues2, 1),
|
||||
Double.MIN_VALUE);
|
||||
|
||||
// Ignore NaNs
|
||||
double[] testValues3 = new double[] {-1, -1, Double.NaN, 1, Double.NaN};
|
||||
TestUtils.assertEquals(
|
||||
new double[] {1, 1,Double.NaN, -1, Double.NaN},
|
||||
MathUtils.normalizeArray(testValues3, 1),
|
||||
Double.MIN_VALUE);
|
||||
|
||||
// Zero sum -> MathArithmeticException
|
||||
double[] zeroSum = new double[] {-1, 1};
|
||||
try {
|
||||
MathUtils.normalizeArray(zeroSum, 1);
|
||||
Assert.fail("expecting MathArithmeticException");
|
||||
} catch (MathArithmeticException ex) {}
|
||||
|
||||
// Infinite elements -> MathArithmeticException
|
||||
double[] hasInf = new double[] {1, 2, 1, Double.NEGATIVE_INFINITY};
|
||||
try {
|
||||
MathUtils.normalizeArray(hasInf, 1);
|
||||
Assert.fail("expecting MathIllegalArgumentException");
|
||||
} catch (MathIllegalArgumentException ex) {}
|
||||
|
||||
// Infinite target -> MathIllegalArgumentException
|
||||
try {
|
||||
MathUtils.normalizeArray(testValues1, Double.POSITIVE_INFINITY);
|
||||
Assert.fail("expecting MathIllegalArgumentException");
|
||||
} catch (MathIllegalArgumentException ex) {}
|
||||
|
||||
// NaN target -> MathIllegalArgumentException
|
||||
try {
|
||||
MathUtils.normalizeArray(testValues1, Double.NaN);
|
||||
Assert.fail("expecting MathIllegalArgumentException");
|
||||
} catch (MathIllegalArgumentException ex) {}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoundDouble() {
|
||||
double x = 1.234567890;
|
||||
|
|
Loading…
Reference in New Issue