| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.referencing; |
| |
| import org.apache.sis.math.Fraction; |
| import org.apache.sis.pending.jdk.JDK21; |
| |
| |
| /** |
| * Optimizes a series expansion in sine terms by using the Clenshaw summation technic. |
| * This class is not a JUnit test, but rather a tools used for generating the Java code |
| * implemented in {@link GeodesicsOnEllipsoid#computeSeriesExpansionCoefficients()}. |
| * This class is hosted in the {@code src/test} directory because we do not want it to |
| * be included in the main code, and we do not have a directory dedicated to code generators. |
| * |
| * <p>The Clenshaw summation technic is summarized in Snyder 3-34 and 3-35. References:</p> |
| * <ul> |
| * <li>Clenshaw, 1955. <u>A note on the summation of Chebyshev series.</u> |
| * Math Tables Other Aids Comput 9(51):118–120.</li> |
| * <li>Snyder, John P. <u>Map Projections - A Working Manual.</u> |
| * U.S. Geological Survey Professional Paper 1395, 1987.</li> |
| * </ul> |
| * |
| * The idea is to rewrite some equations using trigonometric identities. Given: |
| * |
| * <pre class="math"> |
| * s = A⋅sin(θ) + B⋅sin(2θ) + C⋅sin(3θ) + D⋅sin(4θ) + E⋅sin(5θ) + F⋅sin(6θ)</pre> |
| * |
| * We rewrite as: |
| * |
| * <pre class="math"> |
| * s = sinθ⋅(A′ + cosθ⋅(B′ + cosθ⋅(C′ + cosθ⋅(D′ + cosθ⋅(E′ + cosθ⋅F′))))) |
| * A′ = A - C + E |
| * B′ = 2B - 4D + 6F |
| * C′ = 4C - 12E |
| * D′ = 8D - 32F |
| * E′ = 16E |
| * F′ = 32F</pre> |
| * |
| * Some calculations were done in an OpenOffice spreadsheet available on |
| * <a href="https://svn.apache.org/repos/asf/sis/analysis/Map%20projection%20formulas.ods">Subversion</a>. |
| * This class is used for more complex formulas where the use of spreadsheet become too difficult. |
| * |
| * <h2>Limitations</h2> |
| * Current implementation can handle a maximum of 8 terms in the trigonometric series. |
| * This limit is hard-coded in the {@link #compute()} method, but can be expanded by using |
| * the {@link Precomputation} inner class for generating the {@code compute()} code. |
| * |
| * <h4>Possible future evolution</h4> |
| * Maybe we should generate series expansions automatically for a given precision and eccentricity, |
| * adding more terms until the last added term adds a correction smaller than the desired precision. |
| * Then we could use {@link Precomputation} for generating the corresponding Clenshaw summation. |
| * This improvement would be needed for planetary CRS, where map projections may be applied on planet |
| * with higher eccentricity than Earth. |
| * |
| * @author Martin Desruisseaux (Geomatys) |
| * |
| * @see <a href="https://issues.apache.org/jira/browse/SIS-465">SIS-465</a> |
| */ |
| public final class ClenshawSummation { |
| /** |
| * The coefficients to be multiplied by the sine values. |
| * This is the input before Clenshaw summation is applied. |
| */ |
| private final Coefficient[] sineCoefficients; |
| |
| /** |
| * The coefficients to be multiplied by the cosine values. |
| * This is the output after Clenshaw summation is applied. |
| */ |
| private Coefficient[] cosineCoefficients; |
| |
| /** |
| * Creates a new series expansion to be optimized by Clenshaw summation. |
| * Given the following series: |
| * |
| * <pre class="math"> |
| * s = A⋅sin(θ) + B⋅sin(2θ) + C⋅sin(3θ) + D⋅sin(4θ) + E⋅sin(5θ) + F⋅sin(6θ)</pre> |
| * |
| * the arguments given to this constructor shall be A, B, C, D, E and F in that exact order. |
| */ |
| private ClenshawSummation(final Coefficient... coefficients) { |
| this.sineCoefficients = coefficients; |
| } |
| |
| /** |
| * A coefficient to be multiplied by the sine or cosine of an angle. For example in the following expression, |
| * each of A, B, C, D, E and F variable is a {@code Coefficient} instance. |
| * |
| * <pre class="math"> |
| * s = A⋅sin(θ) + B⋅sin(2θ) + C⋅sin(3θ) + D⋅sin(4θ) + E⋅sin(5θ) + F⋅sin(6θ)</pre> |
| * |
| * Each {@code Coefficient} is itself defined by a sum of terms, for example: |
| * |
| * <pre class="math"> |
| * A = -1/2⋅η + 3/16⋅η³ + -1/32⋅η⁵</pre> |
| */ |
| private static final class Coefficient { |
| /** |
| * The terms to add for computing this coefficient. See constructor javadoc for meaning. |
| */ |
| private final Term[] terms; |
| |
| /** |
| * Creates a new coefficient defined by the sum of the given term. Each term is intended to be multiplied |
| * by some η value raised to a different power. Those η values and their powers do not matter for this class |
| * provided that all {@code Coefficient} instances associate the same values and powers at the same indices. |
| */ |
| Coefficient(final Term... terms) { |
| this.terms = terms; |
| } |
| |
| /** |
| * Creates a new coefficient as the sum of all given coefficients multiplied by the given factors. |
| * The {@code toSum[i]} term is multiplied by the {@code factors[i]} at the same index. |
| * This method is used for computing B′ in expressions like: |
| * |
| * <pre class="math"> |
| * B′ = 2B - 4D + 6F</pre> |
| * |
| * @param toSum the terms to sum, ignoring null elements. |
| * @param factors multiplication factor for each term to sum. |
| * If shorter than {@code toSum} array, missing factors are assumed zero. |
| */ |
| static Coefficient sum(final Coefficient[] toSum, final Fraction[] factors) { |
| int n = 0; |
| for (final Coefficient t : toSum) { |
| n = Math.max(n, t.terms.length); |
| } |
| boolean hasTerm = false; |
| final Term[] terms = new Term[n]; |
| final Term[] component = new Term[toSum.length]; |
| for (int i=0; i<n; i++) { |
| for (int j=0; j<toSum.length; j++) { |
| final Term[] t = toSum[j].terms; |
| component[j] = (i < t.length) ? t[i] : null; |
| } |
| hasTerm |= (terms[i] = Term.sum(component, factors)) != null; |
| } |
| return hasTerm ? new Coefficient(terms) : null; |
| } |
| |
| /** |
| * Formats a string representation in the given buffer. |
| */ |
| final void appendTo(final StringBuilder b) { |
| boolean more = false; |
| for (int p = terms.length; --p >= 0;) { // `p` is power minus one. |
| final Term t = terms[p]; |
| if (t != null) { |
| if (more) { |
| b.append(" + "); |
| } |
| t.appendTo(b); |
| b.append("*η"); |
| if (p != 0) { |
| b.append(p+1); |
| } |
| more = true; |
| } |
| } |
| } |
| |
| /** |
| * Returns a string representation for debugging purpose. |
| */ |
| @Override |
| public String toString() { |
| if (terms == null) return ""; |
| final StringBuilder b = new StringBuilder(); |
| appendTo(b); |
| return b.toString(); |
| } |
| } |
| |
| /** |
| * One term in in the evaluation of a {@link Coefficient}. This term is usually single fraction. |
| * For example, a {@code Coefficient} may be defined as below: |
| * |
| * <pre class="math"> |
| * A = -1/2⋅η + 3/16⋅η³ + -1/32⋅η⁵</pre> |
| * |
| * In above example each of -1/2, 3/16 and -1/32 fraction is a {@code Term} instance. |
| * However, this class allows a term to be defined by an array of fractions if each term |
| * is itself defined by another series expansion. |
| */ |
| private static final class Term { |
| /** |
| * The term, usually a single fraction. If this array contains more than one element, |
| * see {@link #Term(Fraction...)} for the meaning. |
| */ |
| private final Fraction[] term; |
| |
| /** |
| * Creates a new term defined by a single fraction. This is the usual case. |
| */ |
| public Term(final int numerator, final int denominator) { |
| term = new Fraction[] {new Fraction(numerator, denominator)}; |
| } |
| |
| /** |
| * Creates a new term which is itself defined by another series expansion. Each fraction is assumed multiplied |
| * by some value raised to a different power. Those values and powers do not matter for this class provided |
| * that all {@code Term} instances associate the same values and powers at the same indices in the given array. |
| */ |
| public Term(final Fraction... term) { |
| this.term = term; |
| } |
| |
| /** |
| * Creates a new term as the sum of all given terms multiplied by the given factors. |
| * The {@code toSum[i]} term is multiplied by the {@code factors[i]} at the same index. |
| * This method is used for computing B′ in expressions like: |
| * |
| * <pre class="math"> |
| * B′ = 2B - 4D + 6F</pre> |
| * |
| * Note that B, D and F above usually contain many terms, so this method will need to be invoked in a loop. |
| * |
| * @param toSum the terms to sum, ignoring null elements. |
| * @param factors multiplication factor for each term to sum. |
| * If shorter than {@code toSum} array, missing factors are assumed zero. |
| */ |
| static Term sum(final Term[] toSum, final Fraction[] factors) { |
| int n = 0; |
| for (final Term t : toSum) { |
| if (t != null) { |
| n = Math.max(n, t.term.length); |
| } |
| } |
| boolean hasTerm = false; |
| final Fraction[] term = new Fraction[n]; |
| for (int i=Math.min(toSum.length, factors.length); --i >= 0;) { |
| final Term t = toSum[i]; |
| final Fraction f = factors[i]; |
| if (t != null && f != null) { |
| for (int j=t.term.length; --j >= 0;) { |
| Fraction ti = t.term[j]; |
| if (ti != null) { |
| ti = ti.multiply(f); |
| Fraction sum = term[j]; |
| if (sum == null) { |
| sum = ti; |
| } else if (ti != null) { |
| sum = sum.add(ti); |
| } |
| term[j] = sum; |
| hasTerm = true; |
| } |
| } |
| } |
| } |
| return hasTerm ? new Term(term) : null; |
| } |
| |
| /** |
| * Formats a string representation in the given buffer. |
| */ |
| final void appendTo(final StringBuilder b) { |
| if (term.length != 1) b.append('('); |
| for (int i=0; i<term.length; i++) { |
| final Fraction t = term[i]; |
| if (i != 0) b.append(" + n*("); |
| if (t == null) { |
| b.append('0'); |
| } else { |
| b.append(t.numerator).append("./").append(t.denominator); |
| } |
| } |
| if (term.length != 1) { |
| JDK21.repeat(b, ')', term.length); |
| } |
| } |
| |
| /** |
| * Returns a string representation for debugging purpose. |
| */ |
| @Override |
| public String toString() { |
| if (term == null) return ""; |
| final StringBuilder b = new StringBuilder(); |
| appendTo(b); |
| return b.toString(); |
| } |
| } |
| |
| /** |
| * Returns a string representation of this object, for debugging purposes or for showing the result. |
| * |
| * @return a string representation of this object before or after summation. |
| */ |
| @Override |
| public String toString() { |
| final StringBuilder b = new StringBuilder().append(" "); |
| boolean more = false; |
| for (int i=0; i<sineCoefficients.length; i++) { |
| final Coefficient t = sineCoefficients[i]; |
| if (t != null) { |
| if (more) b.append("+ "); |
| t.appendTo(b.append('(')); |
| b.append(") * sin("); |
| if (i != 0) b.append(i+1).append('*'); |
| b.append("θ)").append(System.lineSeparator()); |
| more = true; |
| } |
| } |
| if (cosineCoefficients != null) { |
| b.append(System.lineSeparator()).append("= sinθ*"); |
| for (int i=0; i<cosineCoefficients.length; i++) { |
| final Coefficient t = cosineCoefficients[i]; |
| if (i != 0) { |
| b.append(System.lineSeparator()).append(" + cosθ*"); |
| } |
| b.append('('); |
| if (t != null) { |
| t.appendTo(b); |
| } else { |
| b.append('0'); |
| } |
| } |
| JDK21.repeat(b, ')', cosineCoefficients.length); |
| } |
| return b.toString(); |
| } |
| |
| /** |
| * Computes the sum of coefficients multiplied by given factors. |
| */ |
| private Coefficient sum(final int... factors) { |
| final Fraction[] f = new Fraction[factors.length]; |
| for (int i=0; i<f.length; i++) { |
| final int fi = factors[i]; |
| if (fi != 0) { |
| f[i] = new Fraction(fi, 1); |
| } |
| } |
| return Coefficient.sum(sineCoefficients, f); |
| } |
| |
| /** |
| * Performs the Clenshaw summation. Current implementation uses hard-coded coefficients for 8 terms. |
| * If more terms are needed, use {@link Precomputation} for generating the code of this method. |
| * |
| * <h4>Possible future evolution</h4> |
| * It would be possible to compute those terms dynamically using {@link Precomputation}. |
| * It would be useful if a future Apache SIS version generates series expansion on-the-fly |
| * for a specified precision and eccentricity. |
| * |
| * @see <a href="https://issues.apache.org/jira/browse/SIS-465">SIS-465</a> |
| */ |
| private void compute() { |
| cosineCoefficients = new Coefficient[] { |
| sum(1, 0, -1, 0, 1, 0, -1 ), // A′ = A - C + E - G |
| sum(0, 2, 0, -4, 0, 6, 0, -8), // B′ = 2B - 4D + 6F - 8H |
| sum(0, 0, 4, 0, -12, 0, 24 ), // C′ = 4C - 12E + 24G |
| sum(0, 0, 0, 8, 0, -32, 0, 80), // D′ = 8D - 32F + 80H |
| sum(0, 0, 0, 0, 16, 0, -80 ), // E′ = 16E - 80G |
| sum(0, 0, 0, 0, 0, 32, 0, -192), // F′ = 32F - 192H |
| sum(0, 0, 0, 0, 0, 0, 64 ), // G′ = 64G |
| sum(0, 0, 0, 0, 0, 0, 0, 128), // H′ = 128H |
| }; |
| if (sineCoefficients.length > cosineCoefficients.length) { |
| throw new UnsupportedOperationException("Too many coefficients for current implementation."); |
| } |
| } |
| |
| /** |
| * Computes the coefficients that are hard-coded in the {@link #compute()} method. |
| * This class needs to be executed only when the maximal number of terms increased. |
| * The formula is given by Charles F. F. Karney, Geodesics on an ellipsoid of revolution (2011) equation 59: |
| * |
| * <blockquote>f(θ) = ∑(aₙ⋅sin(n⋅θ)</blockquote> |
| * |
| * where the sum is from <var>n</var>=1 to <var>N</var> and <var>N</var> is the maximum number of terms. |
| * The equation can be rewritten as: |
| * |
| * <blockquote>f(θ) = b₁⋅sin(θ)</blockquote> |
| * |
| * where bₙ = |
| * <ul> |
| * <li>0 for <var>n</var> > <var>N</var>,</li> |
| * <li>aₙ + 2⋅bₙ₊₁⋅cos(θ) − bₙ₊₂ otherwise.</li> |
| * </ul> |
| * |
| * This class computes b₁. |
| */ |
| public static final class Precomputation { |
| /** |
| * The factors by which to multiply the aₙ terms. |
| * The first array index identifies the factors which is multiplied, in reverse order. |
| * For example, if there is 4 terms to compute, then the factors are in the following order: |
| * |
| * <ul> |
| * <li>{@code multiplicands[0]} = factors by which to multiply <var>D</var> (a₄).</li> |
| * <li>{@code multiplicands[1]} = factors by which to multiply <var>C</var> (a₃).</li> |
| * <li>{@code multiplicands[2]} = factors by which to multiply <var>B</var> (a₂).</li> |
| * <li>{@code multiplicands[3]} = factors by which to multiply <var>A</var> (a₁).</li> |
| * </ul> |
| * |
| * The second array index is the power by which to multiply {@code cos(θ)}. |
| */ |
| private final int[][] multiplicands; |
| |
| /** |
| * Creates a new step in the iteration process for computing the factors. |
| * This constructor shall be invoked with decreasing <var>n</var> values, |
| * with b₁ computed last. |
| * |
| * @param b1 result from the step at <var>n</var> + 1, or {@code null} if zero. |
| * @param b2 result from the step at <var>n</var> + 2, or {@code null} if zero. |
| */ |
| private Precomputation(final Precomputation b1, final Precomputation b2) { |
| final int length = (b1 != null) ? b1.multiplicands.length + 1 : 1; |
| multiplicands = new int[length][length]; |
| multiplicands[length - 1][0] = 1; |
| if (b2 != null) { |
| // Add −bₙ₊₂ — we add terms at the same power of cos(θ), therefor all indices match. |
| for (int term=0; term < b2.multiplicands.length; term++) { |
| final int max = b2.multiplicands[term].length; |
| for (int power=0; power<max; power++) { |
| multiplicands[term][power] -= b2.multiplicands[term][power]; |
| } |
| } |
| } |
| if (b1 != null) { |
| // Add +2⋅bₙ₊₁⋅cos(θ) — because of cos(θ), power indices are offset by one. |
| for (int term=0; term < b1.multiplicands.length; term++) { |
| final int max = b1.multiplicands[term].length; |
| for (int power=0; power<max; power++) { |
| multiplicands[term][power+1] += 2*b1.multiplicands[term][power]; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns the factors for Clenshaw summation. |
| * |
| * @return string representation of the factors for Clenshaw summation. |
| */ |
| @Override |
| public String toString() { |
| final var sb = new StringBuilder(); |
| for (int power=0; power < multiplicands[0].length; power++) { |
| String separator = "sum("; |
| for (int term=multiplicands.length; --term >= 0;) { |
| sb.append(separator).append(multiplicands[term][power]); |
| separator = ", "; |
| } |
| sb.append("), // ").append((char) ('A' + power)).append("′ = "); |
| char symbol = 'A'; |
| boolean more = false; |
| for (int term=multiplicands.length; --term >= 0; symbol++) { |
| int m = multiplicands[term][power]; |
| if (m != 0) { |
| if (more) { |
| sb.append(' ').append(m < 0 ? '-' : '+'); |
| m = Math.abs(m); |
| } |
| sb.append(' '); |
| if (m != 1) sb.append(m); |
| sb.append(symbol); |
| more = true; |
| } |
| } |
| sb.append(System.lineSeparator()); |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Computes and prints the factors for Clenshaw summation with the given number of terms. |
| * |
| * @param n the desired number of terms. |
| */ |
| public static void run(int n) { |
| Precomputation b2, b1 = null; |
| Precomputation result = null; |
| while (--n >= 0) { |
| b2 = b1; |
| b1 = result; |
| result = new Precomputation(b1, b2); |
| System.out.println(result); |
| } |
| } |
| } |
| |
| /** |
| * Shortcut for {@link Term#Term(int, int)}. |
| */ |
| private static Term t(final int numerator, final int denominator) { |
| return new Term(numerator, denominator); |
| } |
| |
| /** |
| * Returns the series expansion given by Karney (2013) equation 18. This Clenshaw summation is also available in the |
| * <a href="https://svn.apache.org/repos/asf/sis/analysis/Map%20projection%20formulas.ods">Open Office spreadsheet</a>, |
| * but is repeated here in order to compare results. We use this equation for testing that this class works. |
| * The output should be equal to the code in {@link GeodesicsOnEllipsoid#sphericalToEllipsoidalAngle} method, |
| * ignoring {@link GeodesicsOnEllipsoid#A1} and (@code σ} constants. |
| * |
| * @return Karney (2013) equation 18. |
| */ |
| public static ClenshawSummation Karney18() { |
| return new ClenshawSummation( |
| new Coefficient(t(-1, 2), null, t( 3, 16), null, t(-1, 32) ), // C₁₁ |
| new Coefficient(null, t(-1, 16), null, t( 1, 32), null, t(-9, 2048)), // C₁₂ |
| new Coefficient(null, null, t(-1, 48), null, t( 3, 256) ), // C₁₃ |
| new Coefficient(null, null, null, t(-5, 512), null, t( 3, 512)), // C₁₄ |
| new Coefficient(null, null, null, null, t(-7, 1280) ), // C₁₅ |
| new Coefficient(null, null, null, null, null, t(-7, 2048)) // C₁₆ |
| ); |
| } |
| |
| /** |
| * Returns the series expansion given by Karney (2013) equation 25. This series is the reason for this |
| * {@code ClenshawSummation} class since it is too complex for the OpenOffice spreadsheet mentioned in |
| * {@link #Karney18()}. |
| * |
| * @return Karney (2013) equation 25. |
| */ |
| public static ClenshawSummation Karney25() { |
| return new ClenshawSummation( |
| new Coefficient( // C₃₁ |
| new Term(new Fraction(1, 4), new Fraction(-1, 4)), |
| new Term(new Fraction(1, 8), null, new Fraction(-1, 8)), |
| new Term(new Fraction(3, 64), new Fraction( 3, 64), new Fraction(-1, 64)), |
| new Term(new Fraction(5, 128), new Fraction( 1, 64)), |
| new Term(new Fraction(3, 128))), |
| new Coefficient( // C₃₂ |
| null, |
| new Term(new Fraction(1, 16), new Fraction(-3, 32), new Fraction( 1, 32)), |
| new Term(new Fraction(3, 64), new Fraction(-1, 32), new Fraction(-3, 64)), |
| new Term(new Fraction(3, 128), new Fraction( 1, 128)), |
| new Term(new Fraction(5, 256))), |
| new Coefficient( // C₃₃ |
| null, null, |
| new Term(new Fraction(5, 192), new Fraction(-3, 64), new Fraction(5, 192)), |
| new Term(new Fraction(3, 128), new Fraction(-5, 192)), |
| new Term(new Fraction(7, 512))), |
| new Coefficient( // C₃₄ |
| null, null, null, |
| new Term(new Fraction(7, 512), new Fraction(-7, 256)), |
| new Term(new Fraction(7, 512))), |
| new Coefficient( // C₃₅ |
| null, null, null, null, |
| new Term(new Fraction(21, 2560)))); |
| } |
| |
| /** |
| * Coefficients for Rhumb line calculation from Bennett (1996) equation 2. |
| * |
| * @return Bennett (1996) equation 2. |
| */ |
| public static ClenshawSummation Bennett2() { |
| return new ClenshawSummation( |
| new Coefficient(t(-3, 8), t(-3, 32), t(-45, 1024)), |
| new Coefficient(null, t(15, 256), t( 45, 1024)), |
| new Coefficient(null, null, t(-35, 3072)) |
| ); |
| } |
| |
| /** |
| * Coefficients for Equidistant Cylindrical (EPSG:1028) map projection. |
| * |
| * @param inverse {@code false} for the forward projection, or {@code true} for the inverse projection. |
| * |
| * @return Equidistant Cylindrical equation. |
| */ |
| public static ClenshawSummation equidistantCylindrical(final boolean inverse) { |
| if (inverse) { |
| return new ClenshawSummation( |
| new Coefficient(t(3, 2), null, t(-27, 32), null, t(269, 512), null, t(-6607, 24576)), |
| new Coefficient(null, t(21, 16), null, t( -55, 32), null, t(6759, 4096)), |
| new Coefficient(null, null, t(151, 96), null, t(-417, 128), null, t(87963, 20480)), |
| new Coefficient(null, null, null, t(1097, 512), null, t(-15543, 2560)), |
| new Coefficient(null, null, null, null, t(8011, 2560), null, t(-69119, 6144)), |
| new Coefficient(null, null, null, null, null, t( 293393, 61440)), |
| new Coefficient(null, null, null, null, null, null, t(6845701, 860160)) |
| ); |
| } |
| return new ClenshawSummation( |
| new Coefficient(t(-3, 8), t(-3, 32), t(-45, 1024), t(-105, 4096), t(-2205, 131072), t( -6237, 524288), t(-297297, 33554432)), |
| new Coefficient(null, t(15, 256), t( 45, 1024), t( 525, 16384), t( 1575, 65536), t( 155925, 8388608), t(495495, 33554432)), |
| new Coefficient(null, null, t(-35, 3072), t(-175, 12288), t(-3675, 262144), t( -13475, 1048576), t(-385385, 33554432)), |
| new Coefficient(null, null, null, t( 315, 131072), t( 2205, 524288), t( 43659, 8388608), t(189189, 33554432)), |
| new Coefficient(null, null, null, null, t(-693, 1310720), t(-6237, 5242880), t(-297297, 167772160)), |
| new Coefficient(null, null, null, null, null, t( 1001, 8388608), t( 11011, 33554432)), |
| new Coefficient(null, null, null, null, null, null, t( -6435, 234881024)) |
| ); |
| } |
| |
| /** |
| * Computes the Clenshaw summation of a series and display the code to standard output. |
| * This method has been used for generating the Java code implemented in methods such as |
| * {@link GeodesicsOnEllipsoid#computeSeriesExpansionCoefficients()} and may be executed |
| * again if we need to verify the code. |
| * |
| * @param args ignored. |
| */ |
| @SuppressWarnings("UseOfSystemOutOrSystemErr") |
| public static void main(String[] args) { |
| ClenshawSummation s = Karney25(); |
| s.compute(); |
| System.out.println(s); |
| } |
| } |