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:
Gilles Sadowski 2011-10-11 23:37:57 +00:00
parent d64c7a3bfb
commit d092e09531
6 changed files with 110 additions and 107 deletions

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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());
}

View File

@ -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) {}
}
}

View File

@ -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;