sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 01/03: Change in DoubleDouble construction policy: make explicit when an error term is guessed from the 'double' value.
Date Wed, 06 Feb 2019 20:12:17 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit a62ef5a7b83dff5aa883a774b2eacc7785f3e30e
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Wed Feb 6 11:17:26 2019 +0100

    Change in DoubleDouble construction policy: make explicit when an error term is guessed
from the 'double' value.
---
 .../referencing/provider/Equirectangular.java      |  6 +--
 .../sis/referencing/datum/BursaWolfParameters.java |  2 +-
 .../sis/referencing/datum/DefaultEllipsoid.java    | 10 ++---
 .../sis/referencing/datum/TimeDependentBWP.java    |  5 +--
 .../sis/referencing/operation/matrix/Matrices.java |  2 +-
 .../operation/projection/AlbersEqualArea.java      |  4 +-
 .../operation/projection/CylindricalEqualArea.java |  5 +--
 .../operation/projection/Initializer.java          | 19 ++++-----
 .../projection/LambertConicConformal.java          |  7 ++--
 .../referencing/operation/projection/Mercator.java |  7 ++--
 .../operation/projection/PolarStereographic.java   | 10 ++---
 .../operation/projection/TransverseMercator.java   |  2 +-
 .../operation/transform/ContextualParameters.java  |  2 +-
 .../transform/EllipsoidToCentricTransform.java     |  2 +-
 .../org/apache/sis/internal/util/DoubleDouble.java | 48 +++++++++++++---------
 .../apache/sis/internal/util/DoubleDoubleTest.java | 26 +++++++++---
 16 files changed, 89 insertions(+), 68 deletions(-)

diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
index 2b17228..d7e8c31 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
@@ -299,10 +299,10 @@ public final class Equirectangular extends AbstractProvider {
             final double sinφ1 = sin(φ1);
             a = b / (1 - (1 - rs*rs) * (sinφ1*sinφ1));
         }
-        final DoubleDouble k = new DoubleDouble(a);
+        final DoubleDouble k = DoubleDouble.createAndGuessError(a);
         final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
-        denormalize.convertAfter(0, k, new DoubleDouble(fe));
-        denormalize.convertAfter(1, k, new DoubleDouble(fn));
+        denormalize.convertAfter(0, k, DoubleDouble.createAndGuessError(fe));
+        denormalize.convertAfter(1, k, DoubleDouble.createAndGuessError(fn));
         /*
          * Creates the ConcatenatedTransform, letting the factory returns the cached instance
          * if the caller already invoked this method previously (which usually do not happen).
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
index 0a1f1c8..1b26fee 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
@@ -430,7 +430,7 @@ public class BursaWolfParameters extends FormattableObject implements
Cloneable,
             case 6: p = dS; break;
             default: throw new AssertionError(index);
         }
-        return new DoubleDouble(p);
+        return DoubleDouble.createAndGuessError(p);
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
index 8686944..2fceb0e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
@@ -465,13 +465,13 @@ public class DefaultEllipsoid extends AbstractIdentifiedObject implements
Ellips
     private static DoubleDouble flattening(final Ellipsoid e) {
         final DoubleDouble f;
         if (e.isIvfDefinitive()) {
-            f = new DoubleDouble(e.getInverseFlattening());   // Presumed accurate in base
10 (not 2) by definition.
+            f = DoubleDouble.createAndGuessError(e.getInverseFlattening());   // Presumed
accurate in base 10 (not 2) by definition.
             f.inverseDivide(1, 0);
         } else {
-            f = new DoubleDouble(e.getSemiMajorAxis());       // Presumed accurate in base
10 (not 2) by definition.
+            f = DoubleDouble.createAndGuessError(e.getSemiMajorAxis());       // Presumed
accurate in base 10 (not 2) by definition.
             final double value = f.value;
             final double error = f.error;
-            f.subtract(e.getSemiMinorAxis());                 // Presumed accurate in base
10 (not 2) by definition.
+            f.subtract(e.getSemiMinorAxis());                                 // Presumed
accurate in base 10 (not 2) by definition.
             f.divide(value, error);
         }
         return f;
@@ -636,8 +636,8 @@ public class DefaultEllipsoid extends AbstractIdentifiedObject implements
Ellips
     public double semiMajorAxisDifference(final Ellipsoid other) {
         double semiMajor = other.getSemiMajorAxis();
         semiMajor = other.getAxisUnit().getConverterTo(getAxisUnit()).convert(semiMajor);
           // Often a no-op.
-        final DoubleDouble a = new DoubleDouble(semiMajor);     // Presumed accurate in base
10 if no unit conversion.
-        a.subtract(getSemiMajorAxis());                         // Presumed accurate in base
10 (not 2) by definition.
+        final DoubleDouble a = DoubleDouble.createAndGuessError(semiMajor);     // Presumed
accurate in base 10 if no unit conversion.
+        a.subtract(getSemiMajorAxis());                                         // Presumed
accurate in base 10 (not 2) by definition.
         return a.doubleValue();
     }
 
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/TimeDependentBWP.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/TimeDependentBWP.java
index 92e20e0..07a7bde 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/TimeDependentBWP.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/TimeDependentBWP.java
@@ -23,7 +23,6 @@ import org.opengis.referencing.datum.PrimeMeridian;
 import org.apache.sis.internal.util.DoubleDouble;
 
 import static org.apache.sis.util.ArgumentChecks.*;
-import static org.apache.sis.internal.util.DoubleDouble.verbatim;
 import static org.apache.sis.internal.referencing.Formulas.JULIAN_YEAR_LENGTH;
 
 
@@ -160,8 +159,8 @@ public class TimeDependentBWP extends BursaWolfParameters {
     final DoubleDouble period(final Date time) {
         if (time != null) {
             final long millis = time.getTime() - timeReference;
-            if (millis != 0) { // Returns null for 0 as an optimization.
-                final DoubleDouble period = verbatim(millis);
+            if (millis != 0) {                                          // Returns null for
0 as an optimization.
+                final DoubleDouble period = new DoubleDouble(millis);
                 period.divide(1000 * JULIAN_YEAR_LENGTH, 0);
                 return period;
             }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
index a66c03d..8cb69bc 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
@@ -280,7 +280,7 @@ public final class Matrices extends Static {
                          * See the comment in transform(Envelope, Envelope) for an explanation
about why
                          * we use the lower/upper corners instead than getMinimum()/getMaximum()
methods.
                          */
-                        final DoubleDouble scale = new DoubleDouble(same ? +1 : -1, 0);
+                        final DoubleDouble scale = new DoubleDouble(same ? +1d : -1d);
                         scale.multiply(dstEnvelope.getSpan(dstIndex));
                         scale.divide  (srcEnvelope.getSpan(srcIndex));
 
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
index 40962a4..c59b0c2 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
@@ -141,7 +141,7 @@ public class AlbersEqualArea extends EqualAreaProjection {
          * we do not really have that accuracy because of the limited precision of 'nm'.
The intent is rather to
          * increase the chances term cancellations happen during concatenation of coordinate
operations.
          */
-        final DoubleDouble rn = DoubleDouble.verbatim(1);
+        final DoubleDouble rn = new DoubleDouble(1d);
         rn.subtract(initializer.eccentricitySquared);
         rn.divide(nm, 0);
         /*
@@ -149,7 +149,7 @@ public class AlbersEqualArea extends EqualAreaProjection {
          * by the denormalization matrix. Omitted (1-ℯ²) term in nm cancels with omitted
(1-ℯ²) term in qm(…).
          * See above note about double-double arithmetic usage.
          */
-        final DoubleDouble ρ0 = DoubleDouble.verbatim(C - nm*qm(sinφ0));
+        final DoubleDouble ρ0 = new DoubleDouble(C - nm*qm(sinφ0));
         ρ0.sqrt();
         ρ0.multiply(rn);
         /*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
index 24880b7..506eb82 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
@@ -34,7 +34,6 @@ import org.apache.sis.referencing.operation.transform.ContextualParameters;
 import org.apache.sis.util.Workaround;
 
 import static java.lang.Math.*;
-import static org.apache.sis.internal.util.DoubleDouble.verbatim;
 import static org.apache.sis.internal.referencing.provider.LambertCylindricalEqualArea.*;
 
 
@@ -150,7 +149,7 @@ public class CylindricalEqualArea extends EqualAreaProjection {
          * but we nevertheless support it.
          */
         final double φ1 = toRadians(initializer.getAndStore(STANDARD_PARALLEL));
-        final DoubleDouble k0 = verbatim(initializer.scaleAtφ(sin(φ1), cos(φ1)));
+        final DoubleDouble k0 = new DoubleDouble(initializer.scaleAtφ(sin(φ1), cos(φ1)));
         k0.multiply(initializer.getAndStore(Mercator1SP.SCALE_FACTOR));
         /*
          * In most Apache SIS map projection implementations, the scale factor is handled
by the super-class by
@@ -163,7 +162,7 @@ public class CylindricalEqualArea extends EqualAreaProjection {
          * Furthermore we also multiply y by (1-ℯ²)/2 for avoiding the need to recompute
this constant during
          * the projection of every point.
          */
-        final DoubleDouble ik = new DoubleDouble(1, 0);
+        final DoubleDouble ik = new DoubleDouble(1d);
         ik.subtract(initializer.eccentricitySquared);
         ik.multiply(0.5, 0);                 // This line need to be cancelled when using
spherical formulas.
         ik.divide(k0);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
index f2808de..b4adf94 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
@@ -31,7 +31,6 @@ import org.apache.sis.referencing.operation.projection.NormalizedProjection.Para
 
 import static java.lang.Math.*;
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-import static org.apache.sis.internal.util.DoubleDouble.verbatim;
 
 
 /**
@@ -145,7 +144,7 @@ final class Initializer {
                         - getAndStore(roles.get(ParameterRole.FALSE_SOUTHING));
 
         eccentricitySquared = new DoubleDouble();
-        DoubleDouble k = new DoubleDouble(a);  // The value by which to multiply all results
of normalized projection.
+        DoubleDouble k = DoubleDouble.createAndGuessError(a);  // The value by which to multiply
all results of normalized projection.
         if (a != b) {
             if (variant == AUTHALIC_RADIUS) {
                 k.value = Formulas.getAuthalicRadius(a, b);
@@ -177,14 +176,14 @@ final class Initializer {
                  * constructor applies corrections for making those values more accurate
in base 10 rather than 2.
                  */
                 if (isIvfDefinitive) {
-                    final DoubleDouble f = new DoubleDouble(parameters.parameter(Constants.INVERSE_FLATTENING).doubleValue());
+                    final DoubleDouble f = DoubleDouble.createAndGuessError(parameters.parameter(Constants.INVERSE_FLATTENING).doubleValue());
                     f.inverseDivide(1,0);
                     eccentricitySquared.setFrom(f);
                     eccentricitySquared.multiply(2,0);
                     f.square();
                     eccentricitySquared.subtract(f);
                 } else {
-                    final DoubleDouble rs = new DoubleDouble(b);
+                    final DoubleDouble rs = DoubleDouble.createAndGuessError(b);
                     rs.divide(k);                                       // rs = b/a
                     rs.square();
                     eccentricitySquared.value = 1;
@@ -228,8 +227,8 @@ final class Initializer {
          */
         context.normalizeGeographicInputs(λ0);
         final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
-        denormalize.convertAfter(0, k, new DoubleDouble(fe));
-        denormalize.convertAfter(1, k, new DoubleDouble(fn));
+        denormalize.convertAfter(0, k, DoubleDouble.createAndGuessError(fe));
+        denormalize.convertAfter(1, k, DoubleDouble.createAndGuessError(fn));
     }
 
     /**
@@ -283,7 +282,7 @@ final class Initializer {
      * We retrieve this value from the eccentricity with {@code b/a = sqrt(1-ℯ²)}.
      */
     final DoubleDouble axisLengthRatio() {
-        final DoubleDouble b = new DoubleDouble(1,0);
+        final DoubleDouble b = new DoubleDouble(1d);
         b.subtract(eccentricitySquared);
         b.sqrt();
         return b;
@@ -316,9 +315,9 @@ final class Initializer {
      */
     final DoubleDouble rν2(final double sinφ) {
         if (DoubleDouble.DISABLED) {
-            return verbatim(1 - eccentricitySquared.doubleValue() * (sinφ*sinφ));
+            return new DoubleDouble(1 - eccentricitySquared.doubleValue() * (sinφ*sinφ));
         }
-        final DoubleDouble t = verbatim(sinφ);
+        final DoubleDouble t = new DoubleDouble(sinφ);
         t.square();
         t.multiply(eccentricitySquared);
         /*
@@ -345,7 +344,7 @@ final class Initializer {
      * @return radius of the conformal sphere at latitude φ.
      */
     final double radiusOfConformalSphere(final double sinφ) {
-        final DoubleDouble Rc = verbatim(1);
+        final DoubleDouble Rc = new DoubleDouble(1d);
         Rc.subtract(eccentricitySquared);       //  1 - ℯ²
         Rc.sqrt();                              //  √(1 - ℯ²)
         Rc.divide(rν2(sinφ));                   //  √(1 - ℯ²) / (1 - ℯ²sin²φ)
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
index 6061b08..666a7a8 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
@@ -41,7 +41,6 @@ import org.apache.sis.util.Workaround;
 import static java.lang.Math.*;
 import static java.lang.Double.*;
 import static org.apache.sis.math.MathFunctions.isPositive;
-import static org.apache.sis.internal.util.DoubleDouble.verbatim;
 
 
 /**
@@ -289,7 +288,7 @@ public class LambertConicConformal extends ConformalProjection {
          * Opportunistically use double-double arithmetic since the matrix coefficients will
          * be stored in that format anyway. This makes a change in the 2 or 3 last digits.
          */
-        final DoubleDouble F = verbatim(n);
+        final DoubleDouble F = new DoubleDouble(n);
         F.multiply(pow(t1, n), 0);
         F.inverseDivide(m1);
         if (!isNorth) {
@@ -325,11 +324,11 @@ public class LambertConicConformal extends ConformalProjection {
          *   - Multiply by the scale factor (done by the super-class constructor).
          *   - Add false easting and false northing (done by the super-class constructor).
          */
-        DoubleDouble sλ = verbatim(n);
+        DoubleDouble sλ = new DoubleDouble(n);
         DoubleDouble sφ = null;
         if (isNorth) {
             // Reverse the sign of either longitude or latitude values before map projection.
-            sφ = verbatim(-1);
+            sφ = new DoubleDouble(-1d);
         } else {
             sλ.negate();
         }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
index fa52fea..e799998 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
@@ -40,7 +40,6 @@ import org.apache.sis.util.Workaround;
 import static java.lang.Math.*;
 import static java.lang.Double.*;
 import static org.apache.sis.math.MathFunctions.isPositive;
-import static org.apache.sis.internal.util.DoubleDouble.verbatim;
 
 
 /**
@@ -233,7 +232,7 @@ public class Mercator extends ConformalProjection {
          * if they really want, since we sometime see such CRS definitions.
          */
         final double φ1 = toRadians(initializer.getAndStore(Mercator2SP.STANDARD_PARALLEL));
-        final Number k0 = verbatim(initializer.scaleAtφ(sin(φ1), cos(φ1)));
+        final Number k0 = new DoubleDouble(initializer.scaleAtφ(sin(φ1), cos(φ1)));
         /*
          * In principle we should rotate the central meridian (λ0) in the normalization
transform, as below:
          *
@@ -260,7 +259,7 @@ public class Mercator extends ConformalProjection {
             denormalize.convertBefore(0, null, offset);
         }
         if (φ0 != 0) {
-            denormalize.convertBefore(1, null, verbatim(-log(expOfNorthing(φ0, eccentricity
* sin(φ0)))));
+            denormalize.convertBefore(1, null, new DoubleDouble(-log(expOfNorthing(φ0, eccentricity
* sin(φ0)))));
         }
         if (variant == MILLER) {
             normalize  .convertBefore(1, 0.80, null);
@@ -290,7 +289,7 @@ public class Mercator extends ConformalProjection {
          * those remaning lines of code.
          */
         if (φ0 == 0 && isPositive(φ1 != 0 ? φ1 : φ0)) {
-            final Number reverseSign = verbatim(-1);
+            final Number reverseSign = new DoubleDouble(-1d);
             normalize  .convertBefore(1, reverseSign, null);
             denormalize.convertBefore(1, reverseSign, null);        // Must be before false
easting/northing.
         }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
index f746120..f722e40 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
@@ -31,13 +31,13 @@ import org.apache.sis.internal.referencing.provider.PolarStereographicB;
 import org.apache.sis.internal.referencing.provider.PolarStereographicC;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.referencing.Resources;
+import org.apache.sis.internal.util.DoubleDouble;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.util.Workaround;
 import org.apache.sis.measure.Latitude;
 import org.apache.sis.math.MathFunctions;
 
 import static java.lang.Math.*;
-import static org.apache.sis.internal.util.DoubleDouble.verbatim;
 
 
 /**
@@ -207,7 +207,7 @@ public class PolarStereographic extends ConformalProjection {
              *
              * In the spherical case, should give ρ == 2.
              */
-            ρ = verbatim(2 / sqrt(pow(1+eccentricity, 1+eccentricity) * pow(1-eccentricity,
1-eccentricity)));
+            ρ = new DoubleDouble(2 / sqrt(pow(1+eccentricity, 1+eccentricity) * pow(1-eccentricity,
1-eccentricity)));
             ρF = null;
         } else {
             /*
@@ -229,8 +229,8 @@ public class PolarStereographic extends ConformalProjection {
              */
             final double sinφ1 = sin(φ1);
             final double mF = initializer.scaleAtφ(sinφ1, cos(φ1));
-            ρ = verbatim(mF / expOfNorthing(φ1, eccentricity*sinφ1));
-            ρF = (variant == C) ? verbatim(-mF) : null;
+            ρ = new DoubleDouble(mF / expOfNorthing(φ1, eccentricity*sinφ1));
+            ρF = (variant == C) ? new DoubleDouble(-mF) : null;
         }
         /*
          * At this point, all parameters have been processed. Now process to their
@@ -240,7 +240,7 @@ public class PolarStereographic extends ConformalProjection {
         denormalize.convertBefore(0, ρ, null);
         denormalize.convertBefore(1, ρ, ρF);
         if (isNorth) {
-            final Number reverseSign = verbatim(-1);
+            final Number reverseSign = new DoubleDouble(-1d);
             final MatrixSIS normalize = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
             normalize  .convertAfter (1, reverseSign, null);
             denormalize.convertBefore(1, reverseSign, null);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
index 11bcc38..e6b9d45 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
@@ -215,7 +215,7 @@ public class TransverseMercator extends ConformalProjection {
          * in the 3 last digits. Note that we still have sometime a 1 ULP difference compared
to the
          * 'n' value at serialization time.
          */
-        final DoubleDouble t = new DoubleDouble(1, 0);
+        final DoubleDouble t = new DoubleDouble(1d);
         t.subtract(eccentricitySquared, 0);
         t.sqrt();
         t.ratio_1m_1p();
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
index 2d85d47..f7a62cd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
@@ -448,7 +448,7 @@ public class ContextualParameters extends Parameters implements Serializable
{
         final DoubleDouble toRadians = DoubleDouble.createDegreesToRadians();
         DoubleDouble offset = null;
         if (λ0 != 0) {
-            offset = new DoubleDouble(-λ0);
+            offset = DoubleDouble.createAndGuessError(-λ0);
             offset.multiply(toRadians);
         }
         final MatrixSIS normalize = (MatrixSIS) this.normalize;         // Must be the same
instance, not a copy.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
index dcd626e..26a55c2 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
@@ -289,7 +289,7 @@ public class EllipsoidToCentricTransform extends AbstractMathTransform
implement
          *   - A "denormalization" transform for scaling (X,Y,Z) to the semi-major axis length.
          */
         context.normalizeGeographicInputs(0);
-        final DoubleDouble a = new DoubleDouble(semiMajor);
+        final DoubleDouble a = DoubleDouble.createAndGuessError(semiMajor);
         final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
         for (int i=0; i<3; i++) {
             denormalize.convertAfter(i, a, null);
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
index abb6477..48e293b 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
@@ -47,7 +47,7 @@ import org.apache.sis.math.DecimalFunctions;
  * }
  *
  * <div class="section">Impact of availability of FMA instructions</div>
- * If <cite>fused multiply-add</cite> (FMA) instruction are available in a future
Java version
+ * When allowed to use <cite>fused multiply-add</cite> (FMA) instruction added
in JDK9
  * (see <a href="https://issues.apache.org/jira/browse/SIS-136">SIS-136</a> on
Apache SIS JIRA),
  * then the following methods should be revisited:
  *
@@ -56,7 +56,7 @@ import org.apache.sis.math.DecimalFunctions;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  *
  * @see <a href="http://en.wikipedia.org/wiki/Double-double_%28arithmetic%29#Double-double_arithmetic">Wikipedia:
Double-double arithmetic</a>
  *
@@ -244,17 +244,27 @@ public final class DoubleDouble extends Number {
     }
 
     /**
-     * Creates a new value initialized to the given value and an error term inferred by
-     * {@link #errorForWellKnownValue(double)}.
+     * Creates a new instance initialized to the given long integer.
      *
-     * <b>Tip:</b> if the other value is known to be an integer or a power of
2, then invoking
-     * <code>{@linkplain #DoubleDouble(double, double) DoubleDouble}(otherValue, 0)</code>
is more efficient.
+     * @param  value  the long integer value to wrap.
+     */
+    public DoubleDouble(final long value) {
+        this.value = value;
+        this.error = (value - (long) this.value);
+    }
+
+    /**
+     * Creates a new instance initialized to the given value verbatim, without inferring
an error term for double-double arithmetic.
+     * We use this constructor when the value has been computed using transcendental functions
(cosine, logarithm, <i>etc.</i>)
+     * in which case there is no way we can infer a meaningful error term. It should also
be used when the value is known to have
+     * an exact representation as a {@code double} primitive type.
      *
-     * @param  value  the initial value.
+     * @param  value  the value to wrap in a {@code DoubleDouble} instance.
+     *
+     * @see #createAndGuessError(double)
      */
     public DoubleDouble(final double value) {
         this.value = value;
-        this.error = errorForWellKnownValue(value);
     }
 
     /**
@@ -285,17 +295,17 @@ public final class DoubleDouble extends Number {
     }
 
     /**
-     * Uses the given value verbatim, without inferring an error term for double-double arithmetic.
-     * We use this method when the value has been computed using transcendental functions
(cosine,
-     * logarithm, <i>etc.</i>) in which case there is no way we can infer a meaningful
error term.
+     * Creates a new value initialized to the given value and an error term inferred by
+     * {@link #errorForWellKnownValue(double)}.
      *
-     * <p>We use this method both for readability and for making easier to search where
such thing occur.</p>
+     * <b>Tip:</b> if the other value is known to be an integer or a power of
2, then invoking
+     * <code>{@linkplain #DoubleDouble(double) DoubleDouble}(value)</code> is
more efficient.
      *
-     * @param  value  the value to wrap in a {@code DoubleDouble} instance.
-     * @return a {@code DoubleDouble} containing exactly the given value, without error term.
+     * @param  value  the initial value.
+     * @return an instance initialized to the given value and a default error term.
      */
-    public static DoubleDouble verbatim(final double value) {
-        return new DoubleDouble(value, 0);
+    public static DoubleDouble createAndGuessError(final double value) {
+        return new DoubleDouble(value, errorForWellKnownValue(value));
     }
 
     /**
@@ -331,7 +341,7 @@ public final class DoubleDouble extends Number {
     /** @return {@link #value} + {@link #error}. */
     @Override public double doubleValue() {return value + error;}
     @Override public float  floatValue()  {return (float) doubleValue();}
-    @Override public long   longValue()   {return Math.round(doubleValue());}
+    @Override public long   longValue()   {return Math.round(value) + (long) error;}
     @Override public int    intValue()    {return Math.toIntExact(longValue());}
 
     /**
@@ -425,7 +435,7 @@ public final class DoubleDouble extends Number {
      * @param  a  the first number to add.
      * @param  b  the second number to add, which must be smaller than {@code a}.
      */
-    public void setToQuickSum(final double a, final double b) {
+    final void setToQuickSum(final double a, final double b) {
         value = a + b;
         error = b - (value - a);
         if (DISABLED) error = 0;
@@ -997,7 +1007,7 @@ public final class DoubleDouble extends Number {
      * This pattern occurs in map projections.
      */
     public void ratio_1m_1p() {
-        final DoubleDouble numerator = new DoubleDouble(1, 0);
+        final DoubleDouble numerator = new DoubleDouble(1d);
         numerator.subtract(this);
         add(1, 0);
         inverseDivide(numerator);
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/DoubleDoubleTest.java
b/core/sis-utility/src/test/java/org/apache/sis/internal/util/DoubleDoubleTest.java
index 8d10ced..54a2365 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/DoubleDoubleTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/util/DoubleDoubleTest.java
@@ -37,7 +37,7 @@ import static java.lang.StrictMath.*;
  * Those tests need {@link DoubleDouble#DISABLED} to be set to {@code false}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.4
+ * @version 1.0
  * @since   0.4
  * @module
  */
@@ -255,7 +255,7 @@ public final strictfp class DoubleDoubleTest extends TestCase {
     @Test
     @DependsOnMethod("testDivide")
     public void testRatio_1m_1p() {
-        final DoubleDouble t = new DoubleDouble(0.25, 0);
+        final DoubleDouble t = new DoubleDouble(0.25);
         t.ratio_1m_1p();
         assertEquals((1 - 0.25) / (1 + 0.25), t.doubleValue(), STRICT);
     }
@@ -273,7 +273,7 @@ public final strictfp class DoubleDoubleTest extends TestCase {
     @DependsOnMethod({"testMultiply", "testDivide"})
     public void testSqrt() {
         final BigDecimal SQRT2 = new BigDecimal("1.414213562373095048801688724209698");
-        final DoubleDouble dd = new DoubleDouble(2, 0);
+        final DoubleDouble dd = new DoubleDouble(2d);
         dd.sqrt();
         assertNormalizedAndEquals(sqrt(2), dd);
         assertEquals(0, SQRT2.subtract(toBigDecimal(dd)).doubleValue(), 1E-32);
@@ -305,8 +305,8 @@ public final strictfp class DoubleDoubleTest extends TestCase {
     @Test
     @DependsOnMethod({"testMultiply", "testAdd"})
     public void testSeries() {
-        final DoubleDouble t = new DoubleDouble(2);
-        t.series(1, 1./3, 1./9, 1./7, 1./13);  // Random coefficient.
+        final DoubleDouble t = new DoubleDouble(2d);
+        t.series(1, 1./3, 1./9, 1./7, 1./13);                                       // Random
coefficients.
         assertEquals(1 + 2./3 + 4./9 + 8./7 + 16./13, t.doubleValue(), STRICT);
     }
 
@@ -437,4 +437,20 @@ public final strictfp class DoubleDoubleTest extends TestCase {
             assertEquals(DoubleDouble.errorForWellKnownValue(dd.value), dd.error, STRICT);
         }
     }
+
+    /**
+     * Tests initialization with a long value.
+     */
+    @Test
+    public void testLong() {
+        long value = Long.MAX_VALUE - 10;
+        DoubleDouble t = new DoubleDouble(value);
+        assertEquals(-10, t.error, STRICT);
+        assertEquals(value, t.longValue());
+
+        value = Long.MIN_VALUE + 10;
+        t = new DoubleDouble(value);
+        assertEquals(10, t.error, STRICT);
+        assertEquals(value, t.longValue());
+    }
 }


Mime
View raw message