commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From er...@apache.org
Subject svn commit: r952949 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math/stat/descriptive/ main/java/org/apache/commons/math/util/ site/xdoc/ test/java/org/apache/commons/math/stat/descriptive/ test/java/org/apache/commons/math/util/
Date Wed, 09 Jun 2010 10:41:27 GMT
Author: erans
Date: Wed Jun  9 10:41:26 2010
New Revision: 952949

URL: http://svn.apache.org/viewvc?rev=952949&view=rev
Log:
Partially fixing MATH-370 (full resolution is delayed to a major release).

Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/AbstractStorelessUnivariateStatistic.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/StatisticalSummaryValues.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/SummaryStatistics.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java
    commons/proper/math/trunk/src/site/xdoc/changes.xml
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/stat/descriptive/DescriptiveStatisticsTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/AbstractStorelessUnivariateStatistic.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/AbstractStorelessUnivariateStatistic.java?rev=952949&r1=952948&r2=952949&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/AbstractStorelessUnivariateStatistic.java
(original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/AbstractStorelessUnivariateStatistic.java
Wed Jun  9 10:41:26 2010
@@ -165,8 +165,8 @@ public abstract class AbstractStorelessU
             return false;
         }
         AbstractStorelessUnivariateStatistic stat = (AbstractStorelessUnivariateStatistic)
object;
-        return MathUtils.equals(stat.getResult(), this.getResult()) &&
-               MathUtils.equals(stat.getN(), this.getN());
+        return MathUtils.equalsIncludingNaN(stat.getResult(), this.getResult()) &&
+               MathUtils.equalsIncludingNaN(stat.getN(), this.getN());
     }
 
     /**

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java?rev=952949&r1=952948&r2=952949&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java
(original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/MultivariateSummaryStatistics.java
Wed Jun  9 10:41:26 2010
@@ -369,14 +369,14 @@ public class MultivariateSummaryStatisti
             return false;
         }
         MultivariateSummaryStatistics stat = (MultivariateSummaryStatistics) object;
-        return MathUtils.equals(stat.getGeometricMean(), getGeometricMean()) &&
-               MathUtils.equals(stat.getMax(),           getMax())           &&
-               MathUtils.equals(stat.getMean(),          getMean())          &&
-               MathUtils.equals(stat.getMin(),           getMin())           &&
-               MathUtils.equals(stat.getN(),             getN())             &&
-               MathUtils.equals(stat.getSum(),           getSum())           &&
-               MathUtils.equals(stat.getSumSq(),         getSumSq())         &&
-               MathUtils.equals(stat.getSumLog(),        getSumLog())        &&
+        return MathUtils.equalsIncludingNaN(stat.getGeometricMean(), getGeometricMean())
&&
+               MathUtils.equalsIncludingNaN(stat.getMax(),           getMax())          
&&
+               MathUtils.equalsIncludingNaN(stat.getMean(),          getMean())         
&&
+               MathUtils.equalsIncludingNaN(stat.getMin(),           getMin())          
&&
+               MathUtils.equalsIncludingNaN(stat.getN(),             getN())            
&&
+               MathUtils.equalsIncludingNaN(stat.getSum(),           getSum())          
&&
+               MathUtils.equalsIncludingNaN(stat.getSumSq(),         getSumSq())        
&&
+               MathUtils.equalsIncludingNaN(stat.getSumLog(),        getSumLog())       
&&
                stat.getCovariance().equals( getCovariance());
     }
 

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/StatisticalSummaryValues.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/StatisticalSummaryValues.java?rev=952949&r1=952948&r2=952949&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/StatisticalSummaryValues.java
(original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/StatisticalSummaryValues.java
Wed Jun  9 10:41:26 2010
@@ -135,12 +135,12 @@ public class StatisticalSummaryValues im
             return false;
         }
         StatisticalSummaryValues stat = (StatisticalSummaryValues) object;
-        return MathUtils.equals(stat.getMax(),      getMax())  &&
-               MathUtils.equals(stat.getMean(),     getMean()) &&
-               MathUtils.equals(stat.getMin(),      getMin())  &&
-               MathUtils.equals(stat.getN(),        getN())    &&
-               MathUtils.equals(stat.getSum(),      getSum())  &&
-               MathUtils.equals(stat.getVariance(), getVariance());
+        return MathUtils.equalsIncludingNaN(stat.getMax(),      getMax())  &&
+               MathUtils.equalsIncludingNaN(stat.getMean(),     getMean()) &&
+               MathUtils.equalsIncludingNaN(stat.getMin(),      getMin())  &&
+               MathUtils.equalsIncludingNaN(stat.getN(),        getN())    &&
+               MathUtils.equalsIncludingNaN(stat.getSum(),      getSum())  &&
+               MathUtils.equalsIncludingNaN(stat.getVariance(), getVariance());
     }
 
     /**

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/SummaryStatistics.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/SummaryStatistics.java?rev=952949&r1=952948&r2=952949&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/SummaryStatistics.java
(original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/stat/descriptive/SummaryStatistics.java
Wed Jun  9 10:41:26 2010
@@ -360,14 +360,14 @@ public class SummaryStatistics implement
             return false;
         }
         SummaryStatistics stat = (SummaryStatistics)object;
-        return MathUtils.equals(stat.getGeometricMean(), getGeometricMean()) &&
-               MathUtils.equals(stat.getMax(),           getMax())           &&
-               MathUtils.equals(stat.getMean(),          getMean())          &&
-               MathUtils.equals(stat.getMin(),           getMin())           &&
-               MathUtils.equals(stat.getN(),             getN())             &&
-               MathUtils.equals(stat.getSum(),           getSum())           &&
-               MathUtils.equals(stat.getSumsq(),         getSumsq())         &&
-               MathUtils.equals(stat.getVariance(),      getVariance());
+        return MathUtils.equalsIncludingNaN(stat.getGeometricMean(), getGeometricMean())
&&
+               MathUtils.equalsIncludingNaN(stat.getMax(),           getMax())          
&&
+               MathUtils.equalsIncludingNaN(stat.getMean(),          getMean())         
&&
+               MathUtils.equalsIncludingNaN(stat.getMin(),           getMin())          
&&
+               MathUtils.equalsIncludingNaN(stat.getN(),             getN())            
&&
+               MathUtils.equalsIncludingNaN(stat.getSum(),           getSum())          
&&
+               MathUtils.equalsIncludingNaN(stat.getSumsq(),         getSumsq())        
&&
+               MathUtils.equalsIncludingNaN(stat.getVariance(),      getVariance());
     }
 
     /**

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java?rev=952949&r1=952948&r2=952949&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/MathUtils.java Wed
Jun  9 10:41:26 2010
@@ -403,36 +403,68 @@ public final class MathUtils {
     }
 
     /**
-     * Returns true iff both arguments are NaN or neither is NaN and they are
-     * equal
+     * Returns true iff they are equal as defined by
+     * {@link #equals(double,double,int) this method}.
      *
      * @param x first value
      * @param y second value
-     * @return true if the values are equal or both are NaN
+     * @return {@code true} if the values are equal.
+     * @deprecated This method considers that {@code NaN == NaN}. In release
+     * 3.0, the semantics will change in order to comply with IEEE754 where it
+     * is specified that {@code NaN != NaN}.
+     * New methods have been added for those cases wher the old semantics is
+     * useful (see e.g. {@link equalsIncludingNaN(double,double)
+     * equalsIncludingNaN}.
      */
     public static boolean equals(double x, double y) {
         return (Double.isNaN(x) && Double.isNaN(y)) || x == y;
     }
 
     /**
-     * Returns true iff both arguments are equal or within the range of allowed
+     * Returns true if both arguments are NaN or neither is NaN and they are
+     * equal as defined by {@link #equals(double,double) this method}.
+     *
+     * @param x first value
+     * @param y second value
+     * @return {@code true} if the values are equal or both are NaN.
+     */
+    public static boolean equalsIncludingNaN(double x, double y) {
+        return (Double.isNaN(x) && Double.isNaN(y)) || equals(x, y, 1);
+    }
+
+    /**
+     * Returns true if both arguments are equal or within the range of allowed
      * error (inclusive).
-     * <p>
-     * Two NaNs are considered equals, as are two infinities with same sign.
-     * </p>
      *
      * @param x first value
      * @param y second value
-     * @param eps the amount of absolute error to allow
-     * @return true if the values are equal or within range of each other
+     * @param eps the amount of absolute error to allow.
+     * @return {@code true} if the values are equal or within range of each other.
      */
     public static boolean equals(double x, double y, double eps) {
-      return equals(x, y) || (Math.abs(y - x) <= eps);
+        return equals(x, y, 1) || Math.abs(y - x) <= eps;
     }
 
     /**
-     * Returns true iff both arguments are equal or within the range of allowed
+     * Returns true if both arguments are NaN or are equal or within the range
+     * of allowed error (inclusive).
+     *
+     * @param x first value
+     * @param y second value
+     * @param eps the amount of absolute error to allow.
+     * @return {@code true} if the values are equal or within range of each other,
+     * or both are NaN.
+     */
+    public static boolean equalsIncludingNaN(double x, double y, double eps) {
+        return equalsIncludingNaN(x, y) || (Math.abs(y - x) <= eps);
+    }
+
+    /**
+     * Returns true if both arguments are equal or within the range of allowed
      * error (inclusive).
+     * Two float numbers are considered equal if there are {@code (maxUlps - 1)}
+     * (or less) floating point numbers between them (i.e. two adjacent floating
+     * point numbers are considered equal.
      * Adapted from <a
      * href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm">
      * Bruce Dawson</a>
@@ -442,11 +474,11 @@ public final class MathUtils {
      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
      * values between {@code x} and {@code y}.
      * @return {@code true} if there are less than {@code maxUlps} floating
-     * point values between {@code x} and {@code y}
+     * point values between {@code x} and {@code y}.
      */
     public static boolean equals(double x, double y, int maxUlps) {
-        // Check that "maxUlps" is non-negative and small enough so that the
-        // default NAN won't compare as equal to anything.
+        // Check that "maxUlps" is non-negative and small enough so that
+        // NaN won't compare as equal to anything (except another NaN).
         assert maxUlps > 0 && maxUlps < NAN_GAP;
 
         long xInt = Double.doubleToLongBits(x);
@@ -460,18 +492,41 @@ public final class MathUtils {
             yInt = SGN_MASK - yInt;
         }
 
-        return Math.abs(xInt - yInt) <= maxUlps;
+        final boolean isEqual = (Math.abs(xInt - yInt) <= maxUlps);
+
+        return isEqual && !Double.isNaN(x) && !Double.isNaN(y);
     }
 
     /**
-     * Returns true iff both arguments are null or have same dimensions
-     * and all their elements are {@link #equals(double,double) equals}
+     * Returns true if both arguments are NaN or if they are equal as defined
+     * by {@link #equals(double,double,int) this method}.
+     *
+     * @param x first value
+     * @param y second value
+     * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
+     * values between {@code x} and {@code y}.
+     * @return {@code true} if both arguments are NaN or if there are less than
+     * {@code maxUlps} floating point values between {@code x} and {@code y}.
+     */
+    public static boolean equalsIncludingNaN(double x, double y, int maxUlps) {
+        return (Double.isNaN(x) && Double.isNaN(y)) || equals(x, y, maxUlps);
+    }
+
+    /**
+     * Returns true iff both arguments are null or have same dimensions and all
+     * their elements are equal as defined by
+     * {@link #equals(double,double) this method}.
      *
      * @param x first array
      * @param y second array
      * @return true if the values are both null or have same dimension
-     * and equal elements
-     * @since 1.2
+     * and equal elements.
+     * @deprecated This method considers that {@code NaN == NaN}. In release
+     * 3.0, the semantics will change in order to comply with IEEE754 where it
+     * is specified that {@code NaN != NaN}.
+     * New methods have been added for those cases wher the old semantics is
+     * useful (see e.g. {@link equalsIncludingNaN(double[],double[])
+     * equalsIncludingNaN}.
      */
     public static boolean equals(double[] x, double[] y) {
         if ((x == null) || (y == null)) {
@@ -489,6 +544,31 @@ public final class MathUtils {
     }
 
     /**
+     * Returns true iff both arguments are null or have same dimensions and all
+     * their elements are equal as defined by
+     * {@link #equalsIncludingNaN(double,double) this method}.
+     *
+     * @param x first array
+     * @param y second array
+     * @return true if the values are both null or have same dimension and
+     * equal elements
+     */
+    public static boolean equalsIncludingNaN(double[] x, double[] y) {
+        if ((x == null) || (y == null)) {
+            return !((x == null) ^ (y == null));
+        }
+        if (x.length != y.length) {
+            return false;
+        }
+        for (int i = 0; i < x.length; ++i) {
+            if (!equalsIncludingNaN(x[i], y[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * Returns n!. Shorthand for <code>n</code> <a
      * href="http://mathworld.wolfram.com/Factorial.html"> Factorial</a>, the
      * product of the numbers <code>1,...,n</code>.

Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=952949&r1=952948&r2=952949&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Wed Jun  9 10:41:26 2010
@@ -52,6 +52,11 @@ The <action> type attribute can be add,u
     If the output is not quite correct, check for invisible trailing spaces!
      -->
     <release version="2.2" date="TBD" description="TBD">
+      <action dev="erans" type="update" issue="MATH-370">
+        Added new "equalsIncludingNaN" methods that have the same semantics as the old "equals"
methods.
+        These are deprecated, and their semantics will be modified (in the next major release)
such that
+        NaNs are not considered equal (to be more compliant with IEEE754).
+      </action>
       <action dev="luc" type="fix" issue="MATH-352" >
         Added a setQRRankingThreshold method to Levenberg-Marquardt optimizer to improve
robustness
         of rank determination.

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/stat/descriptive/DescriptiveStatisticsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/stat/descriptive/DescriptiveStatisticsTest.java?rev=952949&r1=952948&r2=952949&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/stat/descriptive/DescriptiveStatisticsTest.java
(original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/stat/descriptive/DescriptiveStatisticsTest.java
Wed Jun  9 10:41:26 2010
@@ -210,11 +210,11 @@ public class DescriptiveStatisticsTest e
             dstat.addValue(i);
         }
 
-        assertTrue(MathUtils.equals(mean1, dstat.getMean()));
+        assertTrue(MathUtils.equalsIncludingNaN(mean1, dstat.getMean()));
         dstat.replaceMostRecentValue(0);
-        assertTrue(MathUtils.equals(mean2, dstat.getMean()));
+        assertTrue(MathUtils.equalsIncludingNaN(mean2, dstat.getMean()));
         dstat.removeMostRecentValue();
-        assertTrue(MathUtils.equals(mean3, dstat.getMean()));
+        assertTrue(MathUtils.equalsIncludingNaN(mean3, dstat.getMean()));
 
     }
 

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java?rev=952949&r1=952948&r2=952949&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java
(original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/MathUtilsTest.java
Wed Jun  9 10:41:26 2010
@@ -314,7 +314,7 @@ public final class MathUtilsTest extends
         assertTrue(Double.isNaN(MathUtils.cosh(Double.NaN)));
     }
 
-    public void testEquals() {
+    public void testEqualsIncludingNaN() {
         double[] testArray = {
             Double.NaN,
             Double.POSITIVE_INFINITY,
@@ -324,11 +324,11 @@ public final class MathUtilsTest extends
         for (int i = 0; i < testArray.length; i++) {
             for (int j = 0; j < testArray.length; j++) {
                 if (i == j) {
-                    assertTrue(MathUtils.equals(testArray[i], testArray[j]));
-                    assertTrue(MathUtils.equals(testArray[j], testArray[i]));
+                    assertTrue(MathUtils.equalsIncludingNaN(testArray[i], testArray[j]));
+                    assertTrue(MathUtils.equalsIncludingNaN(testArray[j], testArray[i]));
                 } else {
-                    assertTrue(!MathUtils.equals(testArray[i], testArray[j]));
-                    assertTrue(!MathUtils.equals(testArray[j], testArray[i]));
+                    assertTrue(!MathUtils.equalsIncludingNaN(testArray[i], testArray[j]));
+                    assertTrue(!MathUtils.equalsIncludingNaN(testArray[j], testArray[i]));
                 }
             }
         }
@@ -338,7 +338,7 @@ public final class MathUtilsTest extends
         assertTrue(MathUtils.equals(153.0000, 153.0000, .0625));
         assertTrue(MathUtils.equals(153.0000, 153.0625, .0625));
         assertTrue(MathUtils.equals(152.9375, 153.0000, .0625));
-        assertTrue(MathUtils.equals(Double.NaN, Double.NaN, 1.0));
+        assertFalse(MathUtils.equals(Double.NaN, Double.NaN, 1.0));
         assertTrue(MathUtils.equals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 1.0));
         assertTrue(MathUtils.equals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 1.0));
         assertFalse(MathUtils.equals(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
1.0));
@@ -346,18 +346,44 @@ public final class MathUtilsTest extends
         assertFalse(MathUtils.equals(152.9374, 153.0000, .0625));
     }
 
+    public void testEqualsIncludingNaNWithAllowedDelta() {
+        assertTrue(MathUtils.equalsIncludingNaN(153.0000, 153.0000, .0625));
+        assertTrue(MathUtils.equalsIncludingNaN(153.0000, 153.0625, .0625));
+        assertTrue(MathUtils.equalsIncludingNaN(152.9375, 153.0000, .0625));
+        assertTrue(MathUtils.equalsIncludingNaN(Double.NaN, Double.NaN, 1.0));
+        assertTrue(MathUtils.equalsIncludingNaN(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
1.0));
+        assertTrue(MathUtils.equalsIncludingNaN(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY,
1.0));
+        assertFalse(MathUtils.equalsIncludingNaN(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
1.0));
+        assertFalse(MathUtils.equalsIncludingNaN(153.0000, 153.0625, .0624));
+        assertFalse(MathUtils.equalsIncludingNaN(152.9374, 153.0000, .0625));
+    }
+
     public void testEqualsWithAllowedUlps() {
-        assertTrue(MathUtils.equals(153, 153, 1));
+        assertTrue(MathUtils.equals(0.0, -0.0, 1));
+
+        assertTrue(MathUtils.equals(1.0, 1 + Math.ulp(1d), 1));
+        assertFalse(MathUtils.equals(1.0, 1 + 2 * Math.ulp(1d), 1));
+
+        final double nUp1 = Math.nextUp(1d);
+        final double nnUp1 = Math.nextUp(nUp1);
+        assertTrue(MathUtils.equals(1.0, nUp1, 1));
+        assertTrue(MathUtils.equals(nUp1, nnUp1, 1));
+        assertFalse(MathUtils.equals(1.0, nnUp1, 1));
+
+        assertTrue(MathUtils.equals(0.0, Math.ulp(0d), 1));
+        assertTrue(MathUtils.equals(0.0, -Math.ulp(0d), 1));
+
+        assertTrue(MathUtils.equals(153.0, 153.0, 1));
 
-        assertTrue(MathUtils.equals(153, 153.00000000000003, 1));
-        assertFalse(MathUtils.equals(153, 153.00000000000006, 1));
-        assertTrue(MathUtils.equals(153, 152.99999999999997, 1));
+        assertTrue(MathUtils.equals(153.0, 153.00000000000003, 1));
+        assertFalse(MathUtils.equals(153.0, 153.00000000000006, 1));
+        assertTrue(MathUtils.equals(153.0, 152.99999999999997, 1));
         assertFalse(MathUtils.equals(153, 152.99999999999994, 1));
 
-        assertTrue(MathUtils.equals(-128, -127.99999999999999, 1));
-        assertFalse(MathUtils.equals(-128, -127.99999999999997, 1));
-        assertTrue(MathUtils.equals(-128, -128.00000000000003, 1));
-        assertFalse(MathUtils.equals(-128, -128.00000000000006, 1));
+        assertTrue(MathUtils.equals(-128.0, -127.99999999999999, 1));
+        assertFalse(MathUtils.equals(-128.0, -127.99999999999997, 1));
+        assertTrue(MathUtils.equals(-128.0, -128.00000000000003, 1));
+        assertFalse(MathUtils.equals(-128.0, -128.00000000000006, 1));
 
         assertTrue(MathUtils.equals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, 1));
         assertTrue(MathUtils.equals(Double.MAX_VALUE, Double.POSITIVE_INFINITY, 1));
@@ -365,12 +391,53 @@ public final class MathUtilsTest extends
         assertTrue(MathUtils.equals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 1));
         assertTrue(MathUtils.equals(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY, 1));
 
-
-        assertTrue(MathUtils.equals(Double.NaN, Double.NaN, 1));
+        assertFalse(MathUtils.equals(Double.NaN, Double.NaN, 1));
 
         assertFalse(MathUtils.equals(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
100000));
     }
 
+    public void testEqualsIncludingNaNWithAllowedUlps() {
+        assertTrue(MathUtils.equalsIncludingNaN(0.0, -0.0, 1));
+
+        assertTrue(MathUtils.equalsIncludingNaN(1.0, 1 + Math.ulp(1d), 1));
+        assertFalse(MathUtils.equalsIncludingNaN(1.0, 1 + 2 * Math.ulp(1d), 1));
+
+        final double nUp1 = Math.nextUp(1d);
+        final double nnUp1 = Math.nextUp(nUp1);
+        assertTrue(MathUtils.equalsIncludingNaN(1.0, nUp1, 1));
+        assertTrue(MathUtils.equalsIncludingNaN(nUp1, nnUp1, 1));
+        assertFalse(MathUtils.equalsIncludingNaN(1.0, nnUp1, 1));
+
+        assertTrue(MathUtils.equalsIncludingNaN(0.0, Math.ulp(0d), 1));
+        assertTrue(MathUtils.equalsIncludingNaN(0.0, -Math.ulp(0d), 1));
+
+        assertTrue(MathUtils.equalsIncludingNaN(153.0, 153.0, 1));
+
+        assertTrue(MathUtils.equalsIncludingNaN(153.0, 153.00000000000003, 1));
+        assertFalse(MathUtils.equalsIncludingNaN(153.0, 153.00000000000006, 1));
+        assertTrue(MathUtils.equalsIncludingNaN(153.0, 152.99999999999997, 1));
+        assertFalse(MathUtils.equalsIncludingNaN(153, 152.99999999999994, 1));
+
+        assertTrue(MathUtils.equalsIncludingNaN(-128.0, -127.99999999999999, 1));
+        assertFalse(MathUtils.equalsIncludingNaN(-128.0, -127.99999999999997, 1));
+        assertTrue(MathUtils.equalsIncludingNaN(-128.0, -128.00000000000003, 1));
+        assertFalse(MathUtils.equalsIncludingNaN(-128.0, -128.00000000000006, 1));
+
+        assertTrue(MathUtils.equalsIncludingNaN(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
1));
+        assertTrue(MathUtils.equalsIncludingNaN(Double.MAX_VALUE, Double.POSITIVE_INFINITY,
1));
+
+        assertTrue(MathUtils.equalsIncludingNaN(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY,
1));
+        assertTrue(MathUtils.equalsIncludingNaN(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY,
1));
+
+        assertTrue(MathUtils.equalsIncludingNaN(Double.NaN, Double.NaN, 1));
+
+        assertFalse(MathUtils.equalsIncludingNaN(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
100000));
+    }
+
+    /**
+     * @deprecated To be removed in release 3.0 (replaced by {@link
+     * #testArrayEqualsIncludingNaN()}.
+     */
     public void testArrayEquals() {
         assertFalse(MathUtils.equals(new double[] { 1d }, null));
         assertFalse(MathUtils.equals(null, new double[] { 1d }));
@@ -392,6 +459,26 @@ public final class MathUtilsTest extends
 
     }
 
+    public void testArrayEqualsIncludingNaN() {
+        assertFalse(MathUtils.equalsIncludingNaN(new double[] { 1d }, null));
+        assertFalse(MathUtils.equalsIncludingNaN(null, new double[] { 1d }));
+        assertTrue(MathUtils.equalsIncludingNaN((double[]) null, (double[]) null));
+
+        assertFalse(MathUtils.equalsIncludingNaN(new double[] { 1d }, new double[0]));
+        assertTrue(MathUtils.equalsIncludingNaN(new double[] { 1d }, new double[] { 1d }));
+        assertTrue(MathUtils.equalsIncludingNaN(new double[] {
+                    Double.NaN, Double.POSITIVE_INFINITY,
+                    Double.NEGATIVE_INFINITY, 1d, 0d
+                }, new double[] {
+                    Double.NaN, Double.POSITIVE_INFINITY,
+                    Double.NEGATIVE_INFINITY, 1d, 0d
+                }));
+        assertFalse(MathUtils.equalsIncludingNaN(new double[] { Double.POSITIVE_INFINITY
},
+                                                 new double[] { Double.NEGATIVE_INFINITY
}));
+        assertFalse(MathUtils.equalsIncludingNaN(new double[] { 1d },
+                                                 new double[] { MathUtils.nextAfter(MathUtils.nextAfter(1d,
2d), 2d) }));
+    }
+
     public void testFactorial() {
         for (int i = 1; i < 21; i++) {
             assertEquals(i + "! ", factorial(i), MathUtils.factorial(i));



Mime
View raw message