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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 468894b82c Use of FMA in series expansion of map projections. 
Documentation fixes.
468894b82c is described below

commit 468894b82c294a557433fde891097c958d6b2c5a
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Sat Dec 31 10:48:31 2022 +0100

    Use of FMA in series expansion of map projections.
    Documentation fixes.
---
 .../operation/projection/AuthalicConversion.java   | 18 ++++++++++-----
 .../operation/projection/ConformalProjection.java  | 27 ++++++++++++----------
 .../projection/LambertAzimuthalEqualArea.java      | 12 +---------
 .../operation/projection/MeridianArcBased.java     | 12 +++++-----
 .../operation/transform/LinearTransform1D.java     | 15 +++++++-----
 .../operation/projection/SinusoidalTest.java       |  2 +-
 6 files changed, 44 insertions(+), 42 deletions(-)

diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicConversion.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicConversion.java
index 8c681ea562..902268897b 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicConversion.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicConversion.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.referencing.operation.projection;
 
+import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.referencing.Resources;
 
 import static java.lang.Math.*;
@@ -37,11 +38,11 @@ import static org.apache.sis.math.MathFunctions.atanh;
  * However, this {@code AuthalicConversion} is <strong>not</strong> 
necessarily an authalic projection.
  * Subclasses may want to use the latitude conversion formulas for other 
purposes.
  *
- * <h3>References</h3>
+ * <h2>References</h2>
  * <p>Lee, L. P. "The Nomenclature and Classification of Map Projections." 
Empire Survey Review 7, 190-200, 1944.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   0.8
  */
 abstract class AuthalicConversion extends NormalizedProjection {
@@ -141,9 +142,9 @@ abstract class AuthalicConversion extends 
NormalizedProjection {
          * smallest values first in order to reduce rounding errors. The 
algebraic changes are
          * in 
https://svn.apache.org/repos/asf/sis/analysis/Map%20projection%20formulas.ods.
          */
-        c2β     =      4./7    * e6  +    3./5  * e4  +  2./3 * e2;
-        c4β     =  -3028./2835 * e6  +  -23./45 * e4;
-        c6β     =   1522./2835 * e6;
+        c2β     = fma(e2, 2./3, fma(e4,   3./5,  e6*(    4./7)));
+        c4β     =               fma(e4, -23./45, e6*(-3028./2835));
+        c6β     =                                e6*( 1522./2835);
         qmPolar = qm(1);
         useIterations = (eccentricity >= ECCENTRICITY_THRESHOLD);
     }
@@ -252,7 +253,12 @@ abstract class AuthalicConversion extends 
NormalizedProjection {
          * Snyder 3-18, but rewriten using trigonometric identities in order 
to avoid
          * multiple calls to sin(double) method.
          */
-        double φ = β + cos(β)*sinβ*(c2β + sinβ2*(c4β + sinβ2*c6β));
+        double φ;
+        if (Formulas.USE_FMA) {
+            φ = fma(fma(fma(sinβ2, c6β, c4β), sinβ2, c2β), cos(β)*sinβ, β);
+        } else {
+            φ = β + cos(β)*sinβ*(c2β + sinβ2*(c4β + sinβ2*c6β));
+        }
         if (useIterations) {
             /*
              * Mathematical note: Snyder 3-16 gives q/(1-ℯ²) instead of y in 
the calculation of Δφ below.
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
index f23d690b2a..2e02096618 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.referencing.operation.projection;
 
+import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.referencing.Resources;
 
 import static java.lang.Math.*;
@@ -54,7 +55,7 @@ import static java.lang.Math.*;
  * parallel is a pole, the polar Stereographic results.” (Snyder, page 
105)</div>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.4
  * @since   0.6
  */
 abstract class ConformalProjection extends NormalizedProjection {
@@ -94,12 +95,10 @@ abstract class ConformalProjection extends 
NormalizedProjection {
      *
      *     <blockquote>sin(2χ)⋅(c₂ + cos(2χ)⋅(c₄ + cos(2χ)⋅(c₆ + 
cos(2χ)⋅c₈)))</blockquote>
      *
-     * <div class="note"><b>Serialization note:</b>
-     * we do not strictly need to serialize those fields since they could be 
computed after deserialization.
-     * Bu we serialize them anyway in order to simplify a little bit this 
class (it allows us to keep those
-     * fields final) and because values computed after deserialization could 
be slightly different than the
-     * ones computed after construction if a future version of the constructor 
uses the double-double values
-     * provided by {@link Initializer}.</div>
+     * <h4>Serialization note</h4>
+     * we do not strictly need to serialize those fields because they could be 
computed after deserialization.
+     * But we serialize them anyway in order to simplify a little bit this 
class (it allows us to keep those
+     * fields final) and because different version of SIS computes those 
coefficients in slightly different ways.
      */
     private final double c2χ, c4χ, c6χ, c8χ;
 
@@ -140,10 +139,10 @@ abstract class ConformalProjection extends 
NormalizedProjection {
          * For each line, we add the smallest values first in order to reduce 
rounding errors.
          * The smallest values are the ones using the eccentricity raised to 
the highest power.
          */
-        c2χ =  -73./ 2016 * e8  +   1./40  * e6  +  5./24 * e4  +  1./2 * e2;
-        c4χ =  233./ 6720 * e8  +  29./120 * e6  +  7./24 * e4;
-        c6χ =   81./  280 * e8  +   7./30  * e6;
-        c8χ = 4279./20160 * e8;
+        c2χ = fma(e2, 1./2, fma(e4, 5./24, fma(e6,  1./40,  e8*( -73./2016))));
+        c4χ =               fma(e4, 7./24, fma(e6, 29./120, e8*( 233./6720)));
+        c6χ =                              fma(e6,  7./30,  e8*(  81./280));
+        c8χ =                                               e8*(4279./20160);
     }
 
     /**
@@ -211,7 +210,11 @@ abstract class ConformalProjection extends 
NormalizedProjection {
          */
         final double sin_2φ = sin(2*φ);
         final double cos_2φ = cos(2*φ);
-        φ += sin_2φ * (c2χ + cos_2φ * (c4χ + cos_2φ * (c6χ + cos_2φ * c8χ)));
+        if (Formulas.USE_FMA) {
+            φ = fma(sin_2φ, fma(cos_2φ, fma(cos_2φ, fma(cos_2φ, c8χ, c6χ), 
c4χ), c2χ), φ);
+        } else {
+            φ += sin_2φ * (c2χ + cos_2φ * (c4χ + cos_2φ * (c6χ + cos_2φ * 
c8χ)));
+        }
         /*
          * Note: a previous version checked if the value of the smallest term 
c8χ⋅sin(8φ) was smaller than
          * the iteration tolerance. But this was not reliable enough. We use 
now a hard coded threshold
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
index c6ea7da71a..5599e640e8 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
@@ -42,7 +42,7 @@ import static 
org.apache.sis.internal.referencing.provider.LambertAzimuthalEqual
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Rémi Maréchal (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   1.2
  */
 public class LambertAzimuthalEqualArea extends AuthalicConversion {
@@ -133,16 +133,6 @@ public class LambertAzimuthalEqualArea extends 
AuthalicConversion {
         }
     }
 
-    /**
-     * Creates a new projection initialized to the same parameters than the 
given one.
-     */
-    LambertAzimuthalEqualArea(final LambertAzimuthalEqualArea other) {
-        super(other);
-        sinβ0 = other.sinβ0;
-        cosβ0 = other.cosβ0;
-        polar = other.polar;
-    }
-
     /**
      * Returns the names of additional internal parameters which need to be 
taken in account when
      * comparing two {@code LambertAzimuthalEqualArea} projections or 
formatting them in debug mode.
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
index 4c253979c1..688471ec9a 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
@@ -114,12 +114,12 @@ abstract class MeridianArcBased extends 
NormalizedProjection {
          * of 2, which result in exact representations in IEEE 754 double 
type. Derivation from Kawase formula can be
          * viewed at: 
https://svn.apache.org/repos/asf/sis/analysis/Map%20projection%20formulas.ods
          */
-        cf0 = fma(e10,  -441./0x10000, fma(e8, -175./0x4000, fma(e6,   
-5./0x100, fma(e4,  -3./0x40, fma(e2, -1./4, 1)))));
-        cf1 = fma(e10,  1575./0x20000, fma(e8,  175./0x4000, fma(e6,    
5./0x100, fma(e4,   3./0x40,     e2*(-3./4)))));
-        cf2 = fma(e10, -2625./0x8000,  fma(e8,  175./0x6000, fma(e6, 
5120./0x60000,   e4*(-15./0x20))));
-        cf3 = fma(e10,   735./0x800,   fma(e8, 2240./0x60000,    e6* 
(-35./0x60)));
-        cf4 = fma(e10, -2205./0x1000,      e8*(-315./0x400));
-     // cf5 =     e10*  (693./0x20000)  omitted for now (not yet used).
+        cf0 = fma(e2, -1./4, fma(e4,  -3./0x40, fma(e6,   -5./0x100,   fma(e8, 
-175./0x4000,  e10*( -441./0x10000))))) + 1;
+        cf1 = fma(e2, -3./4, fma(e4,   3./0x40, fma(e6,    5./0x100,   fma(e8, 
 175./0x4000,  e10*( 1575./0x20000)))));
+        cf2 =                fma(e4, -15./0x20, fma(e6, 5120./0x60000, fma(e8, 
 175./0x6000,  e10*(-2625./0x8000))));
+        cf3 =                                   fma(e6,  -35./0x60,    fma(e8, 
2240./0x60000, e10*(  735./0x800)));
+        cf4 =                                                          fma(e8, 
-315./0x400,   e10*(-2205./0x1000));
+     // cf5 =         /* omitted for now (not yet used) */                     
               e10*(  693./0x20000);
         /*
          * Coefficients for inverse transform derived from Snyder 3-26 and 
EPSG guidance notes:
          *
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform1D.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform1D.java
index 18414ac790..606d0d5f55 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform1D.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearTransform1D.java
@@ -80,6 +80,9 @@ class LinearTransform1D extends AbstractMathTransform1D 
implements LinearTransfo
 
     /**
      * Error terms of {@link #scale} and {@link #offset} used in double-double 
arithmetic.
+     * For performance reasons, those terms are not used in {@code 
transform(…)} methods.
+     * They are used in {@link #getMatrix()} for making possible to use 
double-double arithmetic
+     * during the creation of concatenated or inverse transforms.
      */
     private final double scaleError, offsetError;
 
@@ -473,12 +476,12 @@ class LinearTransform1D extends AbstractMathTransform1D 
implements LinearTransfo
                    doubleToRawLongBits(scaleError)  == 
doubleToRawLongBits(that.scaleError) &&
                    doubleToRawLongBits(offsetError) == 
doubleToRawLongBits(that.offsetError);
             /*
-             * NOTE: 'LinearTransform1D' and 'ConstantTransform1D' are heavily 
used by 'Category'
-             * from 'org.apache.sis.coverage' package. It is essential for 
Cateory to differenciate
-             * various NaN values. Because 'equals' is used by 
WeakHashSet.unique(Object) (which
-             * is used by 'DefaultMathTransformFactory'), test for equality 
cannot use the non-raw
-             * doubleToLongBits method because it collapse all NaN into a 
single canonical value.
-             * The 'doubleToRawLongBits' method instead provides the needed 
functionality.
+             * NOTE: `LinearTransform1D` and `ConstantTransform1D` are 
extensively used by `SampleDimension`
+             * in `org.apache.sis.coverage` package. It is essential for 
sample dimensions to differentiate
+             * various NaN values. Because `equals(…)` is used by 
`WeakHashSet.unique(Object)` in turn used
+             * by `DefaultMathTransformFactory`, equality tests cannot use the 
non-raw `doubleToLongBits(…)`
+             * method because it collapse all NaN into a single canonical 
value.
+             * The `doubleToRawLongBits(…)` method instead provides the needed 
functionality.
              */
         }
         return false;
diff --git 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
index 9d487a3617..3bf3efe63c 100644
--- 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
+++ 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/SinusoidalTest.java
@@ -123,7 +123,7 @@ public final class SinusoidalTest extends 
MapProjectionTestCase {
         createProjection(true);
         final double delta = (1.0 / 60) / 1852;                 // 
Approximately 1 metre.
         derivativeDeltas = new double[] {delta, delta};
-        tolerance = Formulas.LINEAR_TOLERANCE / 10;
+        tolerance = Formulas.LINEAR_TOLERANCE / 10000;
         verifyDerivative(105,  30);
         verifyDerivative(100, -60);
     }

Reply via email to