You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2011/01/23 12:06:25 UTC

svn commit: r1062387 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math/util/FastMath.java site/xdoc/changes.xml test/java/org/apache/commons/math/util/FastMathTest.java test/java/org/apache/commons/math/util/MathUtilsTest.java

Author: luc
Date: Sun Jan 23 11:06:24 2011
New Revision: 1062387

URL: http://svn.apache.org/viewvc?rev=1062387&view=rev
Log:
fixed nextAfter implementations for handling of some special values
fixed the signature of the float version, as the spec is to have a double second argument
moved the existing tests that were used in the former implementation in MathUtils,
fixing them also as two of them were not compliant with the spec for equal numbers
Jira: MATH-478

Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java
    commons/proper/math/trunk/src/site/xdoc/changes.xml
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathTest.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/util/FastMath.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java?rev=1062387&r1=1062386&r2=1062387&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/FastMath.java Sun Jan 23 11:06:24 2011
@@ -24,7 +24,6 @@ package org.apache.commons.math.util;
  * <li>{@link #asinh(double)}</li>
  * <li>{@link #acosh(double)}</li>
  * <li>{@link #atanh(double)}</li>
- * <li>{@link #nextAfter(float,float)}</li>
  * </ul>
  * The following methods are found in StrictMath since 1.6 only
  * <ul>
@@ -34,6 +33,7 @@ package org.apache.commons.math.util;
  * <li>{@link #nextUp(double)}</li>
  * <li>{@link #copySign(float, float)}</li>
  * <li>{@link #getExponent(float)}</li>
+ * <li>{@link #nextAfter(float,double)}</li>
  * <li>{@link #nextUp(float)}</li>
  * </ul>
  * @version $Revision$ $Date$
@@ -3420,47 +3420,24 @@ public class FastMath {
     public static double nextAfter(double d, double direction) {
 
         // handling of some important special cases
-        if (Double.isNaN(d)) {
-            return d;
+        if (Double.isNaN(d) || Double.isNaN(direction)) {
+            return Double.NaN;
+        } else if (d == direction) {
+            return direction;
         } else if (Double.isInfinite(d)) {
-            if (d < direction) {
-                return -Double.MAX_VALUE;
-            } else if (direction < d) {
-                return Double.MAX_VALUE;
-            } else {
-                return d;
-            }
+            return (d < 0) ? -Double.MAX_VALUE : Double.MAX_VALUE;
         } else if (d == 0) {
             return (direction < 0) ? -Double.MIN_VALUE : Double.MIN_VALUE;
         }
         // special cases MAX_VALUE to infinity and  MIN_VALUE to 0
         // are handled just as normal numbers
 
-        // split the double in raw components
-        long bits     = Double.doubleToLongBits(d);
-        long sign     = bits & 0x8000000000000000L;
-        long exponent = bits & 0x7ff0000000000000L;
-        long mantissa = bits & 0x000fffffffffffffL;
-
-        if (d * (direction - d) >= 0) {
-            // we should increase the mantissa
-            if (mantissa == 0x000fffffffffffffL) {
-                return Double.longBitsToDouble(sign |
-                                               (exponent + 0x0010000000000000L));
-            } else {
-                return Double.longBitsToDouble(sign |
-                                               exponent | (mantissa + 1));
-            }
+        final long bits = Double.doubleToLongBits(d);
+        final long sign = bits & 0x8000000000000000L;
+        if ((direction < d) ^ (sign == 0L)) {
+            return Double.longBitsToDouble(sign | ((bits & 0x7fffffffffffffffL) + 1));
         } else {
-            // we should decrease the mantissa
-            if (mantissa == 0L) {
-                return Double.longBitsToDouble(sign |
-                                               (exponent - 0x0010000000000000L) |
-                                               0x000fffffffffffffL);
-            } else {
-                return Double.longBitsToDouble(sign |
-                                               exponent | (mantissa - 1));
-            }
+            return Double.longBitsToDouble(sign | ((bits & 0x7fffffffffffffffL) - 1));
         }
 
     }
@@ -3482,45 +3459,27 @@ public class FastMath {
      * direction is greater or smaller than f)
      * @return the next machine representable number in the specified direction
      */
-    public static float nextAfter(float f, float direction) {
+    public static float nextAfter(final float f, final double direction) {
 
         // handling of some important special cases
-        if (Float.isNaN(f)) {
-            return f;
+        if (Double.isNaN(f) || Double.isNaN(direction)) {
+            return Float.NaN;
+        } else if (f == direction) {
+            return (float) direction;
         } else if (Float.isInfinite(f)) {
-            if (f < direction) {
-                return -Float.MAX_VALUE;
-            } else if (direction < f) {
-                return Float.MAX_VALUE;
-            } else {
-                return f;
-            }
+            return (f < 0f) ? -Float.MAX_VALUE : Float.MAX_VALUE;
         } else if (f == 0f) {
-            return (direction < 0f) ? -Float.MIN_VALUE : Float.MIN_VALUE;
+            return (direction < 0) ? -Float.MIN_VALUE : Float.MIN_VALUE;
         }
         // special cases MAX_VALUE to infinity and  MIN_VALUE to 0
         // are handled just as normal numbers
 
-        // split the double in raw components
-        int bits     = Float.floatToIntBits(f);
-        int sign     = bits & 0x80000000;
-        int exponent = bits & 0x7f800000;
-        int mantissa = bits & 0x007fffff;
-
-        if (f * (direction - f) >= 0f) {
-            // we should increase the mantissa
-            if (mantissa == 0x000fffff) {
-                return Float.intBitsToFloat(sign | (exponent + 0x00800000));
-            } else {
-                return Float.intBitsToFloat(sign | exponent | (mantissa + 1));
-            }
+        final int bits = Float.floatToIntBits(f);
+        final int sign = bits & 0x80000000;
+        if ((direction < f) ^ (sign == 0)) {
+            return Float.intBitsToFloat(sign | ((bits & 0x7fffffff) + 1));
         } else {
-            // we should decrease the mantissa
-            if (mantissa == 0) {
-                return Float.intBitsToFloat(sign | (exponent - 0x00800000) | 0x007fffff);
-            } else {
-                return Float.intBitsToFloat(sign | exponent | (mantissa - 1));
-            }
+            return Float.intBitsToFloat(sign | ((bits & 0x7fffffff) - 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=1062387&r1=1062386&r2=1062387&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Sun Jan 23 11:06:24 2011
@@ -183,6 +183,12 @@ The <action> type attribute can be add,u
       </action>
     </release>
     <release version="2.2" date="TBD" description="TBD">
+      <action dev="luc" type="fix" issue="MATH-478">
+          FastMath is not an exact replacement for StrictMath
+          (partially fixed) fixed nextAfter(double, double) and nextAfter(float,double)
+          (beware of the strange double second argument) so that they handle
+          special values in the way as StrictMath
+      </action>
       <action dev="luc" type="fix" issue="MATH-497">
           FastMath is not an exact replacement for StrictMath
           (partially fixed) Add getExponent(double), getExponent(float)

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathTest.java?rev=1062387&r1=1062386&r2=1062387&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/util/FastMathTest.java Sun Jan 23 11:06:24 2011
@@ -976,6 +976,96 @@ public class FastMathTest {
 
     }
 
+    @Test
+    public void testNextAfter() {
+        // 0x402fffffffffffff 0x404123456789abcd -> 4030000000000000
+        Assert.assertEquals(16.0, FastMath.nextAfter(15.999999999999998, 34.27555555555555), 0.0);
+
+        // 0xc02fffffffffffff 0x404123456789abcd -> c02ffffffffffffe
+        Assert.assertEquals(-15.999999999999996, FastMath.nextAfter(-15.999999999999998, 34.27555555555555), 0.0);
+
+        // 0x402fffffffffffff 0x400123456789abcd -> 402ffffffffffffe
+        Assert.assertEquals(15.999999999999996, FastMath.nextAfter(15.999999999999998, 2.142222222222222), 0.0);
+
+        // 0xc02fffffffffffff 0x400123456789abcd -> c02ffffffffffffe
+        Assert.assertEquals(-15.999999999999996, FastMath.nextAfter(-15.999999999999998, 2.142222222222222), 0.0);
+
+        // 0x4020000000000000 0x404123456789abcd -> 4020000000000001
+        Assert.assertEquals(8.000000000000002, FastMath.nextAfter(8.0, 34.27555555555555), 0.0);
+
+        // 0xc020000000000000 0x404123456789abcd -> c01fffffffffffff
+        Assert.assertEquals(-7.999999999999999, FastMath.nextAfter(-8.0, 34.27555555555555), 0.0);
+
+        // 0x4020000000000000 0x400123456789abcd -> 401fffffffffffff
+        Assert.assertEquals(7.999999999999999, FastMath.nextAfter(8.0, 2.142222222222222), 0.0);
+
+        // 0xc020000000000000 0x400123456789abcd -> c01fffffffffffff
+        Assert.assertEquals(-7.999999999999999, FastMath.nextAfter(-8.0, 2.142222222222222), 0.0);
+
+        // 0x3f2e43753d36a223 0x3f2e43753d36a224 -> 3f2e43753d36a224
+        Assert.assertEquals(2.308922399667661E-4, FastMath.nextAfter(2.3089223996676606E-4, 2.308922399667661E-4), 0.0);
+
+        // 0x3f2e43753d36a223 0x3f2e43753d36a223 -> 3f2e43753d36a223
+        Assert.assertEquals(2.3089223996676606E-4, FastMath.nextAfter(2.3089223996676606E-4, 2.3089223996676606E-4), 0.0);
+
+        // 0x3f2e43753d36a223 0x3f2e43753d36a222 -> 3f2e43753d36a222
+        Assert.assertEquals(2.3089223996676603E-4, FastMath.nextAfter(2.3089223996676606E-4, 2.3089223996676603E-4), 0.0);
+
+        // 0x3f2e43753d36a223 0xbf2e43753d36a224 -> 3f2e43753d36a222
+        Assert.assertEquals(2.3089223996676603E-4, FastMath.nextAfter(2.3089223996676606E-4, -2.308922399667661E-4), 0.0);
+
+        // 0x3f2e43753d36a223 0xbf2e43753d36a223 -> 3f2e43753d36a222
+        Assert.assertEquals(2.3089223996676603E-4, FastMath.nextAfter(2.3089223996676606E-4, -2.3089223996676606E-4), 0.0);
+
+        // 0x3f2e43753d36a223 0xbf2e43753d36a222 -> 3f2e43753d36a222
+        Assert.assertEquals(2.3089223996676603E-4, FastMath.nextAfter(2.3089223996676606E-4, -2.3089223996676603E-4), 0.0);
+
+        // 0xbf2e43753d36a223 0x3f2e43753d36a224 -> bf2e43753d36a222
+        Assert.assertEquals(-2.3089223996676603E-4, FastMath.nextAfter(-2.3089223996676606E-4, 2.308922399667661E-4), 0.0);
+
+        // 0xbf2e43753d36a223 0x3f2e43753d36a223 -> bf2e43753d36a222
+        Assert.assertEquals(-2.3089223996676603E-4, FastMath.nextAfter(-2.3089223996676606E-4, 2.3089223996676606E-4), 0.0);
+
+        // 0xbf2e43753d36a223 0x3f2e43753d36a222 -> bf2e43753d36a222
+        Assert.assertEquals(-2.3089223996676603E-4, FastMath.nextAfter(-2.3089223996676606E-4, 2.3089223996676603E-4), 0.0);
+
+        // 0xbf2e43753d36a223 0xbf2e43753d36a224 -> bf2e43753d36a224
+        Assert.assertEquals(-2.308922399667661E-4, FastMath.nextAfter(-2.3089223996676606E-4, -2.308922399667661E-4), 0.0);
+
+        // 0xbf2e43753d36a223 0xbf2e43753d36a223 -> bf2e43753d36a223
+        Assert.assertEquals(-2.3089223996676606E-4, FastMath.nextAfter(-2.3089223996676606E-4, -2.3089223996676606E-4), 0.0);
+
+        // 0xbf2e43753d36a223 0xbf2e43753d36a222 -> bf2e43753d36a222
+        Assert.assertEquals(-2.3089223996676603E-4, FastMath.nextAfter(-2.3089223996676606E-4, -2.3089223996676603E-4), 0.0);
+
+    }
+
+    @Test
+    public void testDoubleNextAfterSpecialCases() {
+        Assert.assertEquals(-Double.MAX_VALUE,FastMath.nextAfter(Double.NEGATIVE_INFINITY, 0D), 0D);
+        Assert.assertEquals(Double.MAX_VALUE,FastMath.nextAfter(Double.POSITIVE_INFINITY, 0D), 0D);
+        Assert.assertEquals(Double.NaN,FastMath.nextAfter(Double.NaN, 0D), 0D);
+        Assert.assertEquals(Double.POSITIVE_INFINITY,FastMath.nextAfter(Double.MAX_VALUE, Double.POSITIVE_INFINITY), 0D);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY,FastMath.nextAfter(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY), 0D);
+        Assert.assertEquals(Double.MIN_VALUE, FastMath.nextAfter(0D, 1D), 0D);
+        Assert.assertEquals(-Double.MIN_VALUE, FastMath.nextAfter(0D, -1D), 0D);
+        Assert.assertEquals(0D, FastMath.nextAfter(Double.MIN_VALUE, -1), 0D);
+        Assert.assertEquals(0D, FastMath.nextAfter(-Double.MIN_VALUE, 1), 0D);
+    }
+
+    @Test
+    public void testFloatNextAfterSpecialCases() {
+        Assert.assertEquals(-Float.MAX_VALUE,FastMath.nextAfter(Float.NEGATIVE_INFINITY, 0F), 0F);
+        Assert.assertEquals(Float.MAX_VALUE,FastMath.nextAfter(Float.POSITIVE_INFINITY, 0F), 0F);
+        Assert.assertEquals(Float.NaN,FastMath.nextAfter(Float.NaN, 0F), 0F);
+        Assert.assertEquals(Float.POSITIVE_INFINITY,FastMath.nextAfter(Float.MAX_VALUE, Float.POSITIVE_INFINITY), 0F);
+        Assert.assertEquals(Float.NEGATIVE_INFINITY,FastMath.nextAfter(-Float.MAX_VALUE, Float.NEGATIVE_INFINITY), 0F);
+        Assert.assertEquals(Float.MIN_VALUE, FastMath.nextAfter(0F, 1F), 0F);
+        Assert.assertEquals(-Float.MIN_VALUE, FastMath.nextAfter(0F, -1F), 0F);
+        Assert.assertEquals(0F, FastMath.nextAfter(Float.MIN_VALUE, -1F), 0F);
+        Assert.assertEquals(0F, FastMath.nextAfter(-Float.MIN_VALUE, 1F), 0F);
+    }
+
     private static void reportError(String message) {
         final boolean fatal = false;
         if (fatal) {

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=1062387&r1=1062386&r2=1062387&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 Jan 23 11:06:24 2011
@@ -958,93 +958,6 @@ public final class MathUtilsTest extends
         }
     }
 
-    public void testNextAfter() {
-        // 0x402fffffffffffff 0x404123456789abcd -> 4030000000000000
-        assertEquals(16.0, FastMath.nextAfter(15.999999999999998, 34.27555555555555), 0.0);
-
-        // 0xc02fffffffffffff 0x404123456789abcd -> c02ffffffffffffe
-        assertEquals(-15.999999999999996, FastMath.nextAfter(-15.999999999999998, 34.27555555555555), 0.0);
-
-        // 0x402fffffffffffff 0x400123456789abcd -> 402ffffffffffffe
-        assertEquals(15.999999999999996, FastMath.nextAfter(15.999999999999998, 2.142222222222222), 0.0);
-
-        // 0xc02fffffffffffff 0x400123456789abcd -> c02ffffffffffffe
-        assertEquals(-15.999999999999996, FastMath.nextAfter(-15.999999999999998, 2.142222222222222), 0.0);
-
-        // 0x4020000000000000 0x404123456789abcd -> 4020000000000001
-        assertEquals(8.000000000000002, FastMath.nextAfter(8.0, 34.27555555555555), 0.0);
-
-        // 0xc020000000000000 0x404123456789abcd -> c01fffffffffffff
-        assertEquals(-7.999999999999999, FastMath.nextAfter(-8.0, 34.27555555555555), 0.0);
-
-        // 0x4020000000000000 0x400123456789abcd -> 401fffffffffffff
-        assertEquals(7.999999999999999, FastMath.nextAfter(8.0, 2.142222222222222), 0.0);
-
-        // 0xc020000000000000 0x400123456789abcd -> c01fffffffffffff
-        assertEquals(-7.999999999999999, FastMath.nextAfter(-8.0, 2.142222222222222), 0.0);
-
-        // 0x3f2e43753d36a223 0x3f2e43753d36a224 -> 3f2e43753d36a224
-        assertEquals(2.308922399667661E-4, FastMath.nextAfter(2.3089223996676606E-4, 2.308922399667661E-4), 0.0);
-
-        // 0x3f2e43753d36a223 0x3f2e43753d36a223 -> 3f2e43753d36a224
-        assertEquals(2.308922399667661E-4, FastMath.nextAfter(2.3089223996676606E-4, 2.3089223996676606E-4), 0.0);
-
-        // 0x3f2e43753d36a223 0x3f2e43753d36a222 -> 3f2e43753d36a222
-        assertEquals(2.3089223996676603E-4, FastMath.nextAfter(2.3089223996676606E-4, 2.3089223996676603E-4), 0.0);
-
-        // 0x3f2e43753d36a223 0xbf2e43753d36a224 -> 3f2e43753d36a222
-        assertEquals(2.3089223996676603E-4, FastMath.nextAfter(2.3089223996676606E-4, -2.308922399667661E-4), 0.0);
-
-        // 0x3f2e43753d36a223 0xbf2e43753d36a223 -> 3f2e43753d36a222
-        assertEquals(2.3089223996676603E-4, FastMath.nextAfter(2.3089223996676606E-4, -2.3089223996676606E-4), 0.0);
-
-        // 0x3f2e43753d36a223 0xbf2e43753d36a222 -> 3f2e43753d36a222
-        assertEquals(2.3089223996676603E-4, FastMath.nextAfter(2.3089223996676606E-4, -2.3089223996676603E-4), 0.0);
-
-        // 0xbf2e43753d36a223 0x3f2e43753d36a224 -> bf2e43753d36a222
-        assertEquals(-2.3089223996676603E-4, FastMath.nextAfter(-2.3089223996676606E-4, 2.308922399667661E-4), 0.0);
-
-        // 0xbf2e43753d36a223 0x3f2e43753d36a223 -> bf2e43753d36a222
-        assertEquals(-2.3089223996676603E-4, FastMath.nextAfter(-2.3089223996676606E-4, 2.3089223996676606E-4), 0.0);
-
-        // 0xbf2e43753d36a223 0x3f2e43753d36a222 -> bf2e43753d36a222
-        assertEquals(-2.3089223996676603E-4, FastMath.nextAfter(-2.3089223996676606E-4, 2.3089223996676603E-4), 0.0);
-
-        // 0xbf2e43753d36a223 0xbf2e43753d36a224 -> bf2e43753d36a224
-        assertEquals(-2.308922399667661E-4, FastMath.nextAfter(-2.3089223996676606E-4, -2.308922399667661E-4), 0.0);
-
-        // 0xbf2e43753d36a223 0xbf2e43753d36a223 -> bf2e43753d36a224
-        assertEquals(-2.308922399667661E-4, FastMath.nextAfter(-2.3089223996676606E-4, -2.3089223996676606E-4), 0.0);
-
-        // 0xbf2e43753d36a223 0xbf2e43753d36a222 -> bf2e43753d36a222
-        assertEquals(-2.3089223996676603E-4, FastMath.nextAfter(-2.3089223996676606E-4, -2.3089223996676603E-4), 0.0);
-
-    }
-
-    public void testDoubleNextAfterSpecialCases() {
-        assertEquals(-Double.MAX_VALUE,FastMath.nextAfter(Double.NEGATIVE_INFINITY, 0D));
-        assertEquals(Double.MAX_VALUE,FastMath.nextAfter(Double.POSITIVE_INFINITY, 0D));
-        assertEquals(Double.NaN,FastMath.nextAfter(Double.NaN, 0D));
-        assertEquals(Double.POSITIVE_INFINITY,FastMath.nextAfter(Double.MAX_VALUE, Double.POSITIVE_INFINITY));
-        assertEquals(Double.NEGATIVE_INFINITY,FastMath.nextAfter(-Double.MAX_VALUE, Double.NEGATIVE_INFINITY));
-        assertEquals(Double.MIN_VALUE, FastMath.nextAfter(0D, 1D), 0D);
-        assertEquals(-Double.MIN_VALUE, FastMath.nextAfter(0D, -1D), 0D);
-        assertEquals(0D, FastMath.nextAfter(Double.MIN_VALUE, -1), 0D);
-        assertEquals(0D, FastMath.nextAfter(-Double.MIN_VALUE, 1), 0D);
-    }
-
-    public void testFloatNextAfterSpecialCases() {
-        assertEquals(-Float.MAX_VALUE,FastMath.nextAfter(Float.NEGATIVE_INFINITY, 0F));
-        assertEquals(Float.MAX_VALUE,FastMath.nextAfter(Float.POSITIVE_INFINITY, 0F));
-        assertEquals(Float.NaN,FastMath.nextAfter(Float.NaN, 0F));
-        assertEquals(Float.POSITIVE_INFINITY,FastMath.nextAfter(Float.MAX_VALUE, Float.POSITIVE_INFINITY));
-        assertEquals(Float.NEGATIVE_INFINITY,FastMath.nextAfter(-Float.MAX_VALUE, Float.NEGATIVE_INFINITY));
-        assertEquals(Float.MIN_VALUE, FastMath.nextAfter(0F, 1F), 0F);
-        assertEquals(-Float.MIN_VALUE, FastMath.nextAfter(0F, -1F), 0F);
-        assertEquals(0F, FastMath.nextAfter(Float.MIN_VALUE, -1F), 0F);
-        assertEquals(0F, FastMath.nextAfter(-Float.MIN_VALUE, 1F), 0F);
-    }
-
     public void testScalb() {
         assertEquals( 0.0, MathUtils.scalb(0.0, 5), 1.0e-15);
         assertEquals(32.0, MathUtils.scalb(1.0, 5), 1.0e-15);