Author: luc
Date: Sun Apr 10 15:56:51 2011
New Revision: 1090820
URL: http://svn.apache.org/viewvc?rev=1090820&view=rev
Log:
Added a compareTo method to MathUtils that uses a number of ulps as a tolerance
error, and works well on all numbers, including normals, subnormals, signed
zeroes, infinities and NaNs
Jira: MATH-557
Modified:
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/util/MathUtilsTest.java
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=1090820&r1=1090819&r2=1090820&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
Sun Apr 10 15:56:51 2011
@@ -400,7 +400,33 @@ public final class MathUtils {
if (equals(x, y, eps)) {
return 0;
} else if (x < y) {
- return -1;
+ return -1;
+ }
+ return 1;
+ }
+
+ /**
+ * Compares two numbers given some amount of allowed error.
+ * Two float numbers are considered equal if there are {@code (maxUlps -
1)}
+ * (or fewer) 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>
+ *
+ * @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 <ul><li>0 if {@link #equals(double, double, int) equals(x, y,
maxUlps)}</li>
+ * <li>< 0 if !{@link #equals(double, double, int) equals(x, y,
maxUlps)} && x < y</li>
+ * <li>> 0 if !{@link #equals(double, double, int) equals(x, y,
maxUlps)} && x > y</li></ul>
+ */
+ public static int compareTo(final double x, final double y, final int
maxUlps) {
+ if (equals(x, y, maxUlps)) {
+ return 0;
+ } else if (x < y) {
+ return -1;
}
return 1;
}
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=1090820&r1=1090819&r2=1090820&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Sun Apr 10 15:56:51 2011
@@ -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="3.0" date="TBD" description="TBD">
+ <action dev="luc" type="add" issue="MATH-557" >
+ Added a compareTo method to MathUtils that uses a number of ulps as a
+ tolerance error, and works well on all numbers, including normals,
subnormals,
+ signed zeroes, infinities and NaNs.
+ </action>
<action dev="luc" type="fix" issue="MATH-434" due-to="Thomas Neidhart">
Fixed two errors in simplex solver when entries are close together or
when variables are not restricted to non-negative.
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=1090820&r1=1090819&r2=1090820&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
Sun Apr 10 15:56:51 2011
@@ -25,7 +25,6 @@ import org.apache.commons.math.TestUtils
import org.apache.commons.math.exception.NonMonotonousSequenceException;
import org.apache.commons.math.exception.MathIllegalArgumentException;
import org.apache.commons.math.exception.MathArithmeticException;
-import org.apache.commons.math.exception.MathRuntimeException;
import org.apache.commons.math.exception.NotFiniteNumberException;
import org.apache.commons.math.exception.NullArgumentException;
import org.apache.commons.math.exception.util.LocalizedFormats;
@@ -308,10 +307,50 @@ public final class MathUtilsTest {
}
@Test
- public void testCompareTo() {
- Assert.assertEquals(0, MathUtils.compareTo(152.33, 152.32, .011));
- Assert.assertTrue(MathUtils.compareTo(152.308, 152.32, .011) < 0);
- Assert.assertTrue(MathUtils.compareTo(152.33, 152.318, .011) > 0);
+ public void testCompareToEpsilon() {
+ Assert.assertEquals(0, MathUtils.compareTo(152.33, 152.32, .011));
+ Assert.assertTrue(MathUtils.compareTo(152.308, 152.32, .011) < 0);
+ Assert.assertTrue(MathUtils.compareTo(152.33, 152.318, .011) > 0);
+ Assert.assertEquals(0, MathUtils.compareTo(Double.MIN_VALUE, +0.0,
Double.MIN_VALUE));
+ Assert.assertEquals(0, MathUtils.compareTo(Double.MIN_VALUE, -0.0,
Double.MIN_VALUE));
+ }
+
+ @Test
+ public void testCompareToMaxUlps() {
+ double a = 152.32;
+ double delta = FastMath.ulp(a);
+ for (int i = 0; i <= 10; ++i) {
+ if (i <= 5) {
+ Assert.assertEquals( 0, MathUtils.compareTo(a, a + i * delta,
5));
+ Assert.assertEquals( 0, MathUtils.compareTo(a, a - i * delta,
5));
+ } else {
+ Assert.assertEquals(-1, MathUtils.compareTo(a, a + i * delta,
5));
+ Assert.assertEquals(+1, MathUtils.compareTo(a, a - i * delta,
5));
+ }
+ }
+
+ Assert.assertEquals( 0, MathUtils.compareTo(-0.0, 0.0, 0));
+
+ Assert.assertEquals(-1, MathUtils.compareTo(-Double.MIN_VALUE, -0.0,
0));
+ Assert.assertEquals( 0, MathUtils.compareTo(-Double.MIN_VALUE, -0.0,
1));
+ Assert.assertEquals(-1, MathUtils.compareTo(-Double.MIN_VALUE, +0.0,
0));
+ Assert.assertEquals( 0, MathUtils.compareTo(-Double.MIN_VALUE, +0.0,
1));
+
+ Assert.assertEquals(+1, MathUtils.compareTo( Double.MIN_VALUE, -0.0,
0));
+ Assert.assertEquals( 0, MathUtils.compareTo( Double.MIN_VALUE, -0.0,
1));
+ Assert.assertEquals(+1, MathUtils.compareTo( Double.MIN_VALUE, +0.0,
0));
+ Assert.assertEquals( 0, MathUtils.compareTo( Double.MIN_VALUE, +0.0,
1));
+
+ Assert.assertEquals(-1, MathUtils.compareTo(-Double.MIN_VALUE,
Double.MIN_VALUE, 0));
+ Assert.assertEquals(-1, MathUtils.compareTo(-Double.MIN_VALUE,
Double.MIN_VALUE, 1));
+ Assert.assertEquals( 0, MathUtils.compareTo(-Double.MIN_VALUE,
Double.MIN_VALUE, 2));
+
+ Assert.assertEquals( 0, MathUtils.compareTo(Double.MAX_VALUE,
Double.POSITIVE_INFINITY, 1));
+ Assert.assertEquals(-1, MathUtils.compareTo(Double.MAX_VALUE,
Double.POSITIVE_INFINITY, 0));
+
+ Assert.assertEquals(+1, MathUtils.compareTo(Double.MAX_VALUE,
Double.NaN, Integer.MAX_VALUE));
+ Assert.assertEquals(+1, MathUtils.compareTo(Double.NaN,
Double.MAX_VALUE, Integer.MAX_VALUE));
+
}
@Test