Modified NormalDistributionImpl.cumulativeProbability to return 0 or 1,
respectively for values more than 40 standard deviations from the mean. For these values, the actual probability is indistinguishable from 0 or 1 as a double. Top coding improves performance for extreme values and prevents convergence exceptions. JIRA: MATH-414 git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1040471 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0615bf8dc0
commit
5fe9b36c45
|
@ -114,26 +114,20 @@ public class NormalDistributionImpl extends AbstractContinuousDistribution
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For this distribution, {@code X}, this method returns {@code P(X < x)}.
|
* For this distribution, {@code X}, this method returns {@code P(X < x)}.
|
||||||
|
* If {@code x}is more than 40 standard deviations from the mean, 0 or 1 is returned,
|
||||||
|
* as in these cases the actual value is within {@code Double.MIN_VALUE} of 0 or 1.
|
||||||
*
|
*
|
||||||
* @param x Value at which the CDF is evaluated.
|
* @param x Value at which the CDF is evaluated.
|
||||||
* @return CDF evaluated at {@code x}.
|
* @return CDF evaluated at {@code x}.
|
||||||
* @throws MathException if the algorithm fails to converge; unless
|
* @throws MathException if the algorithm fails to converge
|
||||||
* {@code x} is more than 20 standard deviations from the mean, in which
|
|
||||||
* case the convergence exception is caught and 0 or 1 is returned.
|
|
||||||
*/
|
*/
|
||||||
public double cumulativeProbability(double x) throws MathException {
|
public double cumulativeProbability(double x) throws MathException {
|
||||||
try {
|
final double dev = x - mean;
|
||||||
return 0.5 * (1.0 + Erf.erf((x - mean) /
|
if (FastMath.abs(dev) > 40 * standardDeviation) {
|
||||||
|
return dev < 0 ? 0.0d : 1.0d;
|
||||||
|
}
|
||||||
|
return 0.5 * (1.0 + Erf.erf((dev) /
|
||||||
(standardDeviation * FastMath.sqrt(2.0))));
|
(standardDeviation * FastMath.sqrt(2.0))));
|
||||||
} catch (MaxIterationsExceededException ex) {
|
|
||||||
if (x < (mean - 20 * standardDeviation)) { // JDK 1.5 blows at 38
|
|
||||||
return 0;
|
|
||||||
} else if (x > (mean + 20 * standardDeviation)) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -118,6 +118,13 @@ The <action> type attribute can be add,update,fix,remove.
|
||||||
</action>
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="2.2" date="TBD" description="TBD">
|
<release version="2.2" date="TBD" description="TBD">
|
||||||
|
<action dev="psteitz" type="fix" issue="MATH-414">
|
||||||
|
Modified NormalDistributionImpl.cumulativeProbability to return 0 or 1,
|
||||||
|
respectively for values more than 40 standard deviations from the mean.
|
||||||
|
For these values, the actual probability is indistinguishable from 0 or 1
|
||||||
|
as a double. Top coding improves performance for extreme values and prevents
|
||||||
|
convergence exceptions.
|
||||||
|
</action>
|
||||||
<action dev="psteitz" type="update" issue="MATH-420">
|
<action dev="psteitz" type="update" issue="MATH-420">
|
||||||
Added toString() override to StatisticalSummaryValues.
|
Added toString() override to StatisticalSummaryValues.
|
||||||
</action>
|
</action>
|
||||||
|
|
|
@ -152,14 +152,16 @@ public class NormalDistributionTest extends ContinuousDistributionAbstractTest
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to make sure top-coding of extreme values works correctly.
|
* Check to make sure top-coding of extreme values works correctly.
|
||||||
* Verifies fix for JIRA MATH-167
|
* Verifies fixes for JIRA MATH-167, MATH-414
|
||||||
*/
|
*/
|
||||||
public void testExtremeValues() throws Exception {
|
public void testExtremeValues() throws Exception {
|
||||||
NormalDistribution distribution = new NormalDistributionImpl(0, 1);
|
NormalDistribution distribution = new NormalDistributionImpl(0, 1);
|
||||||
for (int i = 0; i < 100; i+=5) { // make sure no convergence exception
|
for (int i = 0; i < 100; i++) { // make sure no convergence exception
|
||||||
double lowerTail = distribution.cumulativeProbability(-i);
|
double lowerTail = distribution.cumulativeProbability(-i);
|
||||||
double upperTail = distribution.cumulativeProbability(i);
|
double upperTail = distribution.cumulativeProbability(i);
|
||||||
if (i < 10) { // make sure not top-coded
|
if (i < 9) { // make sure not top-coded
|
||||||
|
// For i = 10, due to bad tail precision in erf (MATH-364), 1 is returned
|
||||||
|
// TODO: once MATH-364 is resolved, replace 9 with 30
|
||||||
assertTrue(lowerTail > 0.0d);
|
assertTrue(lowerTail > 0.0d);
|
||||||
assertTrue(upperTail < 1.0d);
|
assertTrue(upperTail < 1.0d);
|
||||||
}
|
}
|
||||||
|
@ -168,6 +170,12 @@ public class NormalDistributionTest extends ContinuousDistributionAbstractTest
|
||||||
assertTrue(upperTail > 0.99999);
|
assertTrue(upperTail > 0.99999);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertEquals(distribution.cumulativeProbability(Double.MAX_VALUE), 1, 0);
|
||||||
|
assertEquals(distribution.cumulativeProbability(-Double.MAX_VALUE), 0, 0);
|
||||||
|
assertEquals(distribution.cumulativeProbability(Double.POSITIVE_INFINITY), 1, 0);
|
||||||
|
assertEquals(distribution.cumulativeProbability(Double.NEGATIVE_INFINITY), 0, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMath280() throws MathException {
|
public void testMath280() throws MathException {
|
||||||
|
|
Loading…
Reference in New Issue