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 <[email protected]>
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);
}