Return-Path: Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: (qmail 36344 invoked from network); 9 Jun 2010 10:42:20 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 9 Jun 2010 10:42:20 -0000 Received: (qmail 74138 invoked by uid 500); 9 Jun 2010 10:42:20 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 73789 invoked by uid 500); 9 Jun 2010 10:42:17 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 73776 invoked by uid 99); 9 Jun 2010 10:42:16 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 09 Jun 2010 10:42:16 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 09 Jun 2010 10:42:10 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 2F8562388993; Wed, 9 Jun 2010 10:41:27 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit 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 -0000 To: commits@commons.apache.org From: erans@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100609104127.2F8562388993@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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). - *

- * Two NaNs are considered equals, as are two infinities with same sign. - *

* * @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 * Bruce Dawson @@ -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 n Factorial, the * product of the numbers 1,...,n. 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 type attribute can be add,u If the output is not quite correct, check for invisible trailing spaces! --> + + 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). + 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));