You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2021/12/16 12:17:49 UTC

[commons-statistics] 03/05: Avoid overflow in the continuous uniform distribution

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-statistics.git

commit aaf91eb83012564a9f1f1c67c0f1d20ebf7921a6
Author: aherbert <ah...@apache.org>
AuthorDate: Thu Dec 16 11:18:25 2021 +0000

    Avoid overflow in the continuous uniform distribution
    
    The range (upper - lower) must be finite for the current implementation
    to function. If infinite (or nan) then throw an exception.
    
    Ensure the mean is robust to overflow if (lower + upper) is infinite.
---
 .../distribution/UniformContinuousDistribution.java     | 17 +++++++++++------
 .../distribution/UniformContinuousDistributionTest.java |  9 +++++++++
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
index 84b35f7..d9acb29 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
@@ -54,7 +54,8 @@ public final class UniformContinuousDistribution extends AbstractContinuousDistr
      * @param lower Lower bound of this distribution (inclusive).
      * @param upper Upper bound of this distribution (inclusive).
      * @return the distribution
-     * @throws IllegalArgumentException if {@code lower >= upper}.
+     * @throws IllegalArgumentException if {@code lower >= upper} or the range between the bounds
+     * is not finite
      */
     public static UniformContinuousDistribution of(double lower,
                                                    double upper) {
@@ -62,6 +63,9 @@ public final class UniformContinuousDistribution extends AbstractContinuousDistr
             throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GTE_HIGH,
                                             lower, upper);
         }
+        if (!Double.isFinite(upper - lower)) {
+            throw new DistributionException("Range %s is not finite", upper - lower);
+        }
         return new UniformContinuousDistribution(lower, upper);
     }
 
@@ -150,19 +154,20 @@ public final class UniformContinuousDistribution extends AbstractContinuousDistr
     /**
      * {@inheritDoc}
      *
-     * <p>For lower bound {@code lower} and upper bound {@code upper}, the mean is
-     * {@code 0.5 * (lower + upper)}.
+     * <p>For lower bound {@code a} and upper bound {@code b}, the mean is
+     * {@code 0.5 * (a + b)}.
      */
     @Override
     public double getMean() {
-        return 0.5 * (lower + upper);
+        // Avoid overflow
+        return 0.5 * lower + 0.5 * upper;
     }
 
     /**
      * {@inheritDoc}
      *
-     * <p>For lower bound {@code lower} and upper bound {@code upper}, the
-     * variance is {@code (upper - lower)^2 / 12}.
+     * <p>For lower bound {@code a} and upper bound {@code b}, the
+     * variance is {@code (b - a)^2 / 12}.
      */
     @Override
     public double getVariance() {
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
index 28b384a..c56fde0 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
@@ -48,6 +48,10 @@ class UniformContinuousDistributionTest extends BaseContinuousDistributionTest {
         return new Object[][] {
             {0.0, 0.0},
             {1.0, 0.0},
+            // Range not finite
+            {-Double.MAX_VALUE, Double.MAX_VALUE},
+            {Double.NaN, 1.0},
+            {0.0, Double.NaN},
         };
     }
 
@@ -69,6 +73,11 @@ class UniformContinuousDistributionTest extends BaseContinuousDistributionTest {
         dist = UniformContinuousDistribution.of(-1.5, 0.6);
         Assertions.assertEquals(-0.45, dist.getMean());
         Assertions.assertEquals(0.3675, dist.getVariance());
+
+        // Overflow of 0.5 * (lower + upper)
+        dist = UniformContinuousDistribution.of(Double.MAX_VALUE / 2, Double.MAX_VALUE);
+        Assertions.assertEquals(Double.MAX_VALUE - Double.MAX_VALUE / 4, dist.getMean());
+        Assertions.assertEquals(Double.POSITIVE_INFINITY, dist.getVariance());
     }
 
     /**