From 53d9c7fbfbe9cbd7e11cb872ef87e00462fa3eca Mon Sep 17 00:00:00 2001 From: Gilles Sadowski Date: Tue, 16 Apr 2019 12:54:04 +0200 Subject: [PATCH] MATH-1401: Branch added to prevent passing invalid input to "FDistribution". Thanks to Michele De Stefano for circumscribing the issue. --- src/changes/changes.xml | 3 +++ .../stat/interval/ClopperPearsonInterval.java | 14 +++++++++----- .../stat/interval/ClopperPearsonIntervalTest.java | 6 ++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 24012826f..8b5f8e539 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -54,6 +54,9 @@ If the output is not quite correct, check for invisible trailing spaces! + + "ClopperPearsonInterval": Fixed case where number of trials equals number of successes. + "MillerUpdatingRegression": Fixed "ArrayIndexOutOfBounds" exception. diff --git a/src/main/java/org/apache/commons/math4/stat/interval/ClopperPearsonInterval.java b/src/main/java/org/apache/commons/math4/stat/interval/ClopperPearsonInterval.java index b6a72ff4e..5bf642c5c 100644 --- a/src/main/java/org/apache/commons/math4/stat/interval/ClopperPearsonInterval.java +++ b/src/main/java/org/apache/commons/math4/stat/interval/ClopperPearsonInterval.java @@ -46,11 +46,15 @@ public class ClopperPearsonInterval implements BinomialConfidenceInterval { lowerBound = numberOfSuccesses / (numberOfSuccesses + (numberOfTrials - numberOfSuccesses + 1) * fValueLowerBound); - final FDistribution distributionUpperBound = new FDistribution(2 * (numberOfSuccesses + 1), - 2 * (numberOfTrials - numberOfSuccesses)); - final double fValueUpperBound = distributionUpperBound.inverseCumulativeProbability(1 - alpha); - upperBound = (numberOfSuccesses + 1) * fValueUpperBound / - (numberOfTrials - numberOfSuccesses + (numberOfSuccesses + 1) * fValueUpperBound); + if (numberOfSuccesses != numberOfTrials) { + final FDistribution distributionUpperBound = new FDistribution(2 * (numberOfSuccesses + 1), + 2 * (numberOfTrials - numberOfSuccesses)); + final double fValueUpperBound = distributionUpperBound.inverseCumulativeProbability(1 - alpha); + upperBound = (numberOfSuccesses + 1) * fValueUpperBound / + (numberOfTrials - numberOfSuccesses + (numberOfSuccesses + 1) * fValueUpperBound); + } else { + upperBound = 1; + } } return new ConfidenceInterval(lowerBound, upperBound, confidenceLevel); diff --git a/src/test/java/org/apache/commons/math4/stat/interval/ClopperPearsonIntervalTest.java b/src/test/java/org/apache/commons/math4/stat/interval/ClopperPearsonIntervalTest.java index e50ab581b..a8a1db1a3 100644 --- a/src/test/java/org/apache/commons/math4/stat/interval/ClopperPearsonIntervalTest.java +++ b/src/test/java/org/apache/commons/math4/stat/interval/ClopperPearsonIntervalTest.java @@ -40,4 +40,10 @@ public class ClopperPearsonIntervalTest extends BinomialConfidenceIntervalAbstra Assert.assertEquals(0.1248658, confidenceInterval.getUpperBound(), 1E-5); } + @Test + public void testMath1401() { + ConfidenceInterval interval = new ClopperPearsonInterval().createInterval(1, 1, 0.95); + Assert.assertEquals(0.025, interval.getLowerBound(), 1e-16); + Assert.assertEquals(1, interval.getUpperBound(), 0d); + } }