sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1540002 - in /sis/branches/JDK7/core/sis-utility/src: main/java/org/apache/sis/internal/util/ main/java/org/apache/sis/math/ test/java/org/apache/sis/math/
Date Fri, 08 Nov 2013 12:47:41 GMT
Author: desruisseaux
Date: Fri Nov  8 12:47:40 2013
New Revision: 1540002

URL: http://svn.apache.org/r1540002
Log:
Take sign in account, and check for the domain of validity.

Modified:
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/DecimalFunctions.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/DecimalFunctionsTest.java

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java?rev=1540002&r1=1540001&r2=1540002&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
[UTF-8] Fri Nov  8 12:47:40 2013
@@ -291,10 +291,10 @@ public final class Numerics extends Stat
     /**
      * Returns the significand <var>m</var> of the given value such as {@code
value = m×2ⁿ}
      * where <var>n</var> is {@link Math#getExponent(double)} - {@value #SIGNIFICAND_SIZE}.
-     * For any non-NaN positive values (including infinity), the following relationship holds:
+     * For any non-NaN values (including infinity), the following relationship holds:
      *
      * {@preformat java
-     *    assert Math.scalb(getSignificand(value), Math.getExponent(value) - SIGNIFICAND_SIZE)
== value;
+     *    assert Math.scalb(getSignificand(value), Math.getExponent(value) - SIGNIFICAND_SIZE)
== Math.abs(value);
      * }
      *
      * For negative values, this method behaves as if the value was positive.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/DecimalFunctions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/DecimalFunctions.java?rev=1540002&r1=1540001&r2=1540002&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/DecimalFunctions.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/DecimalFunctions.java
[UTF-8] Fri Nov  8 12:47:40 2013
@@ -148,7 +148,7 @@ public final class DecimalFunctions exte
             return value; // Integer, infinity or NaN.
         }
         final int m = Numerics.getSignificand(value);
-        assert Math.scalb((float) m, e) == value : value;
+        assert Math.scalb((float) m, e) == Math.abs(value) : value;
         /*
          * Get the factor c for converting the significand m from base 2 to base 10, such
as:
          *
@@ -173,13 +173,14 @@ public final class DecimalFunctions exte
         if (Math.abs(r - mc) >= c/2) {
             r = Math.rint(mc);
         }
-        return Math.scalb(r / c, e);
+        return Math.copySign(Math.scalb(r / c, e), value);
     }
 
     /**
      * Returns the difference between the given {@code double} value and the representation
of that value in base 10.
-     * This method is <em>approximatively</em> equivalent to the following code,
except that it is potentially faster
-     * since the actual implementation avoid the creation of {@link java.math.BigDecimal}
objects:
+     * For any value in the method's domain of validity (defined below), this method is <em>approximatively</em>
+     * equivalent to the following code except that it is potentially faster since the actual
implementation
+     * avoids the creation of {@link java.math.BigDecimal} objects:
      *
      * {@preformat java
      *   BigDecimal base2  = new BigDecimal(value);     // Exact same value as stored in
IEEE 754 format.
@@ -202,9 +203,15 @@ public final class DecimalFunctions exte
      * map projection parameters defined by national mapping agencies.
      * </font></blockquote>
      *
+     * {@section Domain of validity}
+     * The current implementation has a hole for {@code abs(value) < 3E-8} approximatively,
except for the 0
+     * value which is supported. For any non-zero value closer to zero than the above-cited
threshold, this
+     * method returns {@code NaN} because it currently can not compute the delta with enough
accuracy.
+     * This limitation may change in any future SIS version if we found a better algorithm.
+     *
      * @param  value The value for which to get the delta compared to its base 10 representation.
-     * @return The delta that would need to be added to the given {@code double} value for
getting
-     *         a result closer to its base 10 representation.
+     * @return The delta that would need to be added to the given {@code double} value for
getting a result
+     *         closer to its base 10 representation, or {@link Double#NaN} if it can not
be computed.
      */
     public static double deltaForDoubleToDecimal(final double value) {
         /*
@@ -217,8 +224,11 @@ public final class DecimalFunctions exte
         if (e >= 0) {
             return 0; // Integer, infinity or NaN.
         }
+        if (e < -24 - SIGNIFICAND_SIZE) {         // 2.9802322E-8 threshold found empirically.
+            return (e == -1075) ? 0 : Double.NaN; // Returns 0 for the 0 value, NaN for all
others.
+        }
         final long m = Numerics.getSignificand(value);
-        assert Math.scalb((double) m, e) == value : value;
+        assert Math.scalb((double) m, e) == Math.abs(value) : value;
         final int e10 = -Numerics.toExp10(e); // Range: [0 … 324] inclusive.
         /*
          * If we were continuing with the same strategy than in floatToDouble(float), we
would compute:
@@ -284,7 +294,7 @@ public final class DecimalFunctions exte
         /*
          * We are done: unscale and return.
          */
-        final double delta = -Math.scalb(mc / cs, e);
+        final double delta = MathFunctions.xorSign(-Math.scalb(mc / cs, e), value);
         assert Math.abs(delta) <= Math.ulp(value) / 2 : value;
         return delta;
     }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java?rev=1540002&r1=1540001&r2=1540002&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
[UTF-8] Fri Nov  8 12:47:40 2013
@@ -307,6 +307,14 @@ public final class MathFunctions extends
      *        is a special case since it is used for scaling axes or formatting human-readable
      *        output.}
      *
+     * Special cases:
+     * <ul>
+     *   <li>If <var>x</var> is equals or lower than -324, then the result
is 0.</li>
+     *   <li>If <var>x</var> is equals or greater than 309, then the result
is {@link Double#POSITIVE_INFINITY}.</li>
+     *   <li>If <var>x</var> is in the [0 … 18] range inclusive, then
the result is exact.</li>
+     *   <li>For all other <var>x</var> values, the result is the closest
IEEE 754 approximation.</li>
+     * </ul>
+     *
      * @param x The exponent.
      * @return 10 raised to the given exponent.
      */

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/DecimalFunctionsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/DecimalFunctionsTest.java?rev=1540002&r1=1540001&r2=1540002&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/DecimalFunctionsTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/math/DecimalFunctionsTest.java
[UTF-8] Fri Nov  8 12:47:40 2013
@@ -63,10 +63,12 @@ public final strictfp class DecimalFunct
      * since the former will delegate to the later in this test.
      */
     @Test
+    @DependsOnMethod("testConstants")
     public void testPow10() {
         for (int i=EXPONENT_FOR_ZERO; i<=EXPONENT_FOR_MAX; i++) { // Range of allowed
exponents in base 10.
             assertEquals(parseDouble("1E"+i), pow10(i), STRICT);
         }
+        assertEquals(1000000000000000000L, Math.round(pow10(18))); // Highest value having
an exact representation.
     }
 
     /**
@@ -75,23 +77,30 @@ public final strictfp class DecimalFunct
     @Test
     @DependsOnMethod("testPow10")
     public void testFloatToDouble() {
-        assertEquals(0.0,    floatToDouble(0.0f),    0);
-        assertEquals(-0.0,   floatToDouble(-0.0f),   0);
-        assertEquals(10,     floatToDouble(10f),     0);
-        assertEquals(0.1,    floatToDouble(0.1f),    0);
-        assertEquals(0.01,   floatToDouble(0.01f),   0);
-        assertEquals(0.001,  floatToDouble(0.001f),  0);
-        assertEquals(0.0001, floatToDouble(0.0001f), 0);
-        assertEquals(3.7E-8, floatToDouble(3.7E-8f), 0);
-        assertEquals(3.7E-9, floatToDouble(3.7E-9f), 0);
+        assertEquals(NaN,               floatToDouble(Float.NaN),               STRICT);
+        assertEquals(POSITIVE_INFINITY, floatToDouble(Float.POSITIVE_INFINITY), STRICT);
+        assertEquals(NEGATIVE_INFINITY, floatToDouble(Float.NEGATIVE_INFINITY), STRICT);
+
+        assertEquals( 0.0,    floatToDouble( 0.0f),    STRICT);
+        assertEquals(-0.0,    floatToDouble(-0.0f),    STRICT);
+        assertEquals( 10,     floatToDouble( 10f),     STRICT);
+        assertEquals(-10,     floatToDouble(-10f),     STRICT);
+        assertEquals( 0.1,    floatToDouble( 0.1f),    STRICT);
+        assertEquals( 0.01,   floatToDouble( 0.01f),   STRICT);
+        assertEquals(-0.01,   floatToDouble(-0.01f),   STRICT);
+        assertEquals( 0.001,  floatToDouble( 0.001f),  STRICT);
+        assertEquals( 0.0001, floatToDouble( 0.0001f), STRICT);
+        assertEquals( 3.7E-8, floatToDouble( 3.7E-8f), STRICT);
+        assertEquals( 3.7E-9, floatToDouble( 3.7E-9f), STRICT);
+
         final Random random = TestUtilities.createRandomNumberGenerator();
         for (int i=0; i<100; i++) {
-            final float value = StrictMath.scalb(random.nextFloat(), random.nextInt(20) -
10);
+            float value = StrictMath.scalb(random.nextFloat(), random.nextInt(20) - 10);
+            if (random.nextBoolean()) {
+                value = -value;
+            }
             assertEquals(String.valueOf(value), String.valueOf(floatToDouble(value)));
         }
-        assertEquals(POSITIVE_INFINITY, floatToDouble(Float.POSITIVE_INFINITY), STRICT);
-        assertEquals(NEGATIVE_INFINITY, floatToDouble(Float.NEGATIVE_INFINITY), STRICT);
-        assertEquals(NaN,               floatToDouble(Float.NaN),               STRICT);
     }
 
     /**
@@ -151,11 +160,17 @@ public final strictfp class DecimalFunct
         assertEquals( 4.8633955884724856E-23, deltaForDoubleToDecimal(0.8234936921177336),
   4E-32); //  5666840 ULP
         assertEquals(-2.1507730707526207E-25, deltaForDoubleToDecimal(0.19920566694813302),
  2E-33); // 36267774 ULP
         for (int i=0; i<50; i++) {
-            final double     ieee  = random.nextDouble();
+            double ieee = StrictMath.scalb(random.nextDouble(), 20 - random.nextInt(48));
+            if (random.nextBoolean()) {
+                ieee = -ieee;
+            }
             final String     text  = String.valueOf(ieee);
             final BigDecimal value = new BigDecimal(text);
             final double     delta = value.subtract(new BigDecimal(ieee)).doubleValue();
-            assertEquals(text, delta, deltaForDoubleToDecimal(ieee), StrictMath.ulp(ieee)
* 1E-12);
+            final double    actual = deltaForDoubleToDecimal(ieee);
+            if (!Double.isNaN(actual)) {
+                assertEquals(text, delta, actual, StrictMath.ulp(ieee) * 1E-12);
+            }
         }
     }
 



Mime
View raw message