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)}.
|
||||
* 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.
|
||||
* @return CDF evaluated at {@code x}.
|
||||
* @throws MathException if the algorithm fails to converge; unless
|
||||
* {@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.
|
||||
* @throws MathException if the algorithm fails to converge
|
||||
*/
|
||||
public double cumulativeProbability(double x) throws MathException {
|
||||
try {
|
||||
return 0.5 * (1.0 + Erf.erf((x - mean) /
|
||||
(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;
|
||||
}
|
||||
final double dev = 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))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -118,6 +118,13 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
</action>
|
||||
</release>
|
||||
<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">
|
||||
Added toString() override to StatisticalSummaryValues.
|
||||
</action>
|
||||
|
|
|
@ -152,14 +152,16 @@ public class NormalDistributionTest extends ContinuousDistributionAbstractTest
|
|||
|
||||
/**
|
||||
* 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 {
|
||||
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 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(upperTail < 1.0d);
|
||||
}
|
||||
|
@ -168,6 +170,12 @@ public class NormalDistributionTest extends ContinuousDistributionAbstractTest
|
|||
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 {
|
||||
|
|
Loading…
Reference in New Issue