diff --git a/src/main/java/org/apache/commons/math/distribution/NormalDistributionImpl.java b/src/main/java/org/apache/commons/math/distribution/NormalDistributionImpl.java
index 456555bf3..0d7ce7da3 100644
--- a/src/main/java/org/apache/commons/math/distribution/NormalDistributionImpl.java
+++ b/src/main/java/org/apache/commons/math/distribution/NormalDistributionImpl.java
@@ -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))));
}
/**
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 339854ddd..0c4519b03 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -118,6 +118,13 @@ The type attribute can be add,update,fix,remove.
+
+ 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.
+
Added toString() override to StatisticalSummaryValues.
diff --git a/src/test/java/org/apache/commons/math/distribution/NormalDistributionTest.java b/src/test/java/org/apache/commons/math/distribution/NormalDistributionTest.java
index e9ffe5c1e..f8ebebf68 100644
--- a/src/test/java/org/apache/commons/math/distribution/NormalDistributionTest.java
+++ b/src/test/java/org/apache/commons/math/distribution/NormalDistributionTest.java
@@ -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 {