GeographicLib  2.6
EllipticFunction.cpp
Go to the documentation of this file.
1 /**
2  * \file EllipticFunction.cpp
3  * \brief Implementation for GeographicLib::EllipticFunction class
4  *
5  * Copyright (c) Charles Karney (2008-2024) <karney@alum.mit.edu> and licensed
6  * under the MIT/X11 License. For more information, see
7  * https://geographiclib.sourceforge.io/
8  **********************************************************************/
9 
11 
12 namespace GeographicLib {
13 
14  using namespace std;
15 
16  /*
17  * Implementation of methods given in
18  *
19  * B. C. Carlson
20  * Computation of elliptic integrals
21  * Numerical Algorithms 10, 13-26 (1995)
22  */
23 
24  Math::real EllipticFunction::RF(real x, real y, real z) {
25  // Carlson, eqs 2.2 - 2.7
26  static const real tolRF =
27  pow(3 * numeric_limits<real>::epsilon() * real(0.01), 1/real(8));
28  real
29  A0 = (x + y + z)/3,
30  An = A0,
31  Q = fmax(fmax(fabs(A0-x), fabs(A0-y)), fabs(A0-z)) / tolRF,
32  x0 = x,
33  y0 = y,
34  z0 = z,
35  mul = 1;
36  while (Q >= mul * fabs(An)) {
37  // Max 6 trips
38  real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0);
39  An = (An + lam)/4;
40  x0 = (x0 + lam)/4;
41  y0 = (y0 + lam)/4;
42  z0 = (z0 + lam)/4;
43  mul *= 4;
44  }
45  real
46  X = (A0 - x) / (mul * An),
47  Y = (A0 - y) / (mul * An),
48  Z = - (X + Y),
49  E2 = X*Y - Z*Z,
50  E3 = X*Y*Z;
51  // https://dlmf.nist.gov/19.36.E1
52  // Polynomial is
53  // (1 - E2/10 + E3/14 + E2^2/24 - 3*E2*E3/44
54  // - 5*E2^3/208 + 3*E3^2/104 + E2^2*E3/16)
55  // convert to Horner form...
56  return (E3 * (6930 * E3 + E2 * (15015 * E2 - 16380) + 17160) +
57  E2 * ((10010 - 5775 * E2) * E2 - 24024) + 240240) /
58  (240240 * sqrt(An));
59  }
60 
61  Math::real EllipticFunction::RF(real x, real y) {
62  // Carlson, eqs 2.36 - 2.38
63  static const real tolRG0 =
64  real(2.7) * sqrt((numeric_limits<real>::epsilon() * real(0.01)));
65  real xn = sqrt(x), yn = sqrt(y);
66  if (xn < yn) swap(xn, yn);
67  while (fabs(xn-yn) > tolRG0 * xn) {
68  // Max 4 trips
69  real t = (xn + yn) /2;
70  yn = sqrt(xn * yn);
71  xn = t;
72  }
73  return Math::pi() / (xn + yn);
74  }
75 
76  Math::real EllipticFunction::RC(real x, real y) {
77  // Defined only for y != 0 and x >= 0.
78  return ( !(x >= y) ? // x < y and catch nans
79  // https://dlmf.nist.gov/19.2.E18
80  atan(sqrt((y - x) / x)) / sqrt(y - x) :
81  ( x == y ? 1 / sqrt(y) :
82  asinh( y > 0 ?
83  // https://dlmf.nist.gov/19.2.E19
84  // atanh(sqrt((x - y) / x))
85  sqrt((x - y) / y) :
86  // https://dlmf.nist.gov/19.2.E20
87  // atanh(sqrt(x / (x - y)))
88  sqrt(-x / y) ) / sqrt(x - y) ) );
89  }
90 
91  Math::real EllipticFunction::RG(real x, real y, real z) {
92  return (x == 0 ? RG(y, z) :
93  (y == 0 ? RG(z, x) :
94  (z == 0 ? RG(x, y) :
95  // Carlson, eq 1.7
96  (z * RF(x, y, z) - (x-z) * (y-z) * RD(x, y, z) / 3
97  + sqrt(x * y / z)) / 2 )));
98  }
99 
101  // Carlson, eqs 2.36 - 2.39
102  static const real tolRG0 =
103  real(2.7) * sqrt((numeric_limits<real>::epsilon() * real(0.01)));
104  real
105  x0 = sqrt(fmax(x, y)),
106  y0 = sqrt(fmin(x, y)),
107  xn = x0,
108  yn = y0,
109  s = 0,
110  mul = real(0.25);
111  while (fabs(xn-yn) > tolRG0 * xn) {
112  // Max 4 trips
113  real t = (xn + yn) /2;
114  yn = sqrt(xn * yn);
115  xn = t;
116  mul *= 2;
117  t = xn - yn;
118  s += mul * t * t;
119  }
120  return (Math::sq( (x0 + y0)/2 ) - s) * Math::pi() / (2 * (xn + yn));
121  }
122 
123  Math::real EllipticFunction::RJ(real x, real y, real z, real p) {
124  // Carlson, eqs 2.17 - 2.25
125  static const real
126  tolRD = pow(real(0.2) * (numeric_limits<real>::epsilon() * real(0.01)),
127  1/real(8));
128  real
129  A0 = (x + y + z + 2*p)/5,
130  An = A0,
131  delta = (p-x) * (p-y) * (p-z),
132  Q = fmax(fmax(fabs(A0-x), fabs(A0-y)),
133  fmax(fabs(A0-z), fabs(A0-p))) / tolRD,
134  x0 = x,
135  y0 = y,
136  z0 = z,
137  p0 = p,
138  mul = 1,
139  mul3 = 1,
140  s = 0;
141  while (Q >= mul * fabs(An)) {
142  // Max 7 trips
143  real
144  lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0),
145  d0 = (sqrt(p0)+sqrt(x0)) * (sqrt(p0)+sqrt(y0)) * (sqrt(p0)+sqrt(z0)),
146  e0 = delta/(mul3 * Math::sq(d0));
147  s += RC(1, 1 + e0)/(mul * d0);
148  An = (An + lam)/4;
149  x0 = (x0 + lam)/4;
150  y0 = (y0 + lam)/4;
151  z0 = (z0 + lam)/4;
152  p0 = (p0 + lam)/4;
153  mul *= 4;
154  mul3 *= 64;
155  }
156  real
157  X = (A0 - x) / (mul * An),
158  Y = (A0 - y) / (mul * An),
159  Z = (A0 - z) / (mul * An),
160  P = -(X + Y + Z) / 2,
161  E2 = X*Y + X*Z + Y*Z - 3*P*P,
162  E3 = X*Y*Z + 2*P * (E2 + 2*P*P),
163  E4 = (2*X*Y*Z + P * (E2 + 3*P*P)) * P,
164  E5 = X*Y*Z*P*P;
165  // https://dlmf.nist.gov/19.36.E2
166  // Polynomial is
167  // (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26
168  // - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272
169  // - 9*(E3*E4+E2*E5)/68)
170  return ((471240 - 540540 * E2) * E5 +
171  (612612 * E2 - 540540 * E3 - 556920) * E4 +
172  E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) +
173  E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) /
174  (4084080 * mul * An * sqrt(An)) + 6 * s;
175  }
176 
177  Math::real EllipticFunction::RD(real x, real y, real z) {
178  // Carlson, eqs 2.28 - 2.34
179  static const real
180  tolRD = pow(real(0.2) * (numeric_limits<real>::epsilon() * real(0.01)),
181  1/real(8));
182  real
183  A0 = (x + y + 3*z)/5,
184  An = A0,
185  Q = fmax(fmax(fabs(A0-x), fabs(A0-y)), fabs(A0-z)) / tolRD,
186  x0 = x,
187  y0 = y,
188  z0 = z,
189  mul = 1,
190  s = 0;
191  while (Q >= mul * fabs(An)) {
192  // Max 7 trips
193  real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0);
194  s += 1/(mul * sqrt(z0) * (z0 + lam));
195  An = (An + lam)/4;
196  x0 = (x0 + lam)/4;
197  y0 = (y0 + lam)/4;
198  z0 = (z0 + lam)/4;
199  mul *= 4;
200  }
201  real
202  X = (A0 - x) / (mul * An),
203  Y = (A0 - y) / (mul * An),
204  Z = -(X + Y) / 3,
205  E2 = X*Y - 6*Z*Z,
206  E3 = (3*X*Y - 8*Z*Z)*Z,
207  E4 = 3 * (X*Y - Z*Z) * Z*Z,
208  E5 = X*Y*Z*Z*Z;
209  // https://dlmf.nist.gov/19.36.E2
210  // Polynomial is
211  // (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26
212  // - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272
213  // - 9*(E3*E4+E2*E5)/68)
214  return ((471240 - 540540 * E2) * E5 +
215  (612612 * E2 - 540540 * E3 - 556920) * E4 +
216  E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) +
217  E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) /
218  (4084080 * mul * An * sqrt(An)) + 3 * s;
219  }
220 
221  void EllipticFunction::Reset(real k2, real alpha2,
222  real kp2, real alphap2) {
223  // Accept nans here (needed for GeodesicExact)
224  if (k2 > 1)
225  throw GeographicErr("Parameter k2 is not in (-inf, 1]");
226  if (alpha2 > 1)
227  throw GeographicErr("Parameter alpha2 is not in (-inf, 1]");
228  if (kp2 < 0)
229  throw GeographicErr("Parameter kp2 is not in [0, inf)");
230  if (alphap2 < 0)
231  throw GeographicErr("Parameter alphap2 is not in [0, inf)");
232  _k2 = k2;
233  _kp2 = kp2;
234  _alpha2 = alpha2;
235  _alphap2 = alphap2;
236  _eps = _k2/Math::sq(sqrt(_kp2) + 1);
237  // Values of complete elliptic integrals for k = 0,1 and alpha = 0,1
238  // K E D
239  // k = 0: pi/2 pi/2 pi/4
240  // k = 1: inf 1 inf
241  // Pi G H
242  // k = 0, alpha = 0: pi/2 pi/2 pi/4
243  // k = 1, alpha = 0: inf 1 1
244  // k = 0, alpha = 1: inf inf pi/2
245  // k = 1, alpha = 1: inf inf inf
246  //
247  // Pi(0, k) = K(k)
248  // G(0, k) = E(k)
249  // H(0, k) = K(k) - D(k)
250  // Pi(0, k) = K(k)
251  // G(0, k) = E(k)
252  // H(0, k) = K(k) - D(k)
253  // Pi(alpha2, 0) = pi/(2*sqrt(1-alpha2))
254  // G(alpha2, 0) = pi/(2*sqrt(1-alpha2))
255  // H(alpha2, 0) = pi/(2*(1 + sqrt(1-alpha2)))
256  // Pi(alpha2, 1) = inf
257  // H(1, k) = K(k)
258  // G(alpha2, 1) = H(alpha2, 1) = RC(1, alphap2)
259  if (_k2 != 0) {
260  // Complete elliptic integral K(k), Carlson eq. 4.1
261  // https://dlmf.nist.gov/19.25.E1
262  _kKc = _kp2 != 0 ? RF(_kp2, 1) : Math::infinity();
263  // Complete elliptic integral E(k), Carlson eq. 4.2
264  // https://dlmf.nist.gov/19.25.E1
265  _eEc = _kp2 != 0 ? 2 * RG(_kp2, 1) : 1;
266  // D(k) = (K(k) - E(k))/k^2, Carlson eq.4.3
267  // https://dlmf.nist.gov/19.25.E1
268  _dDc = _kp2 != 0 ? RD(0, _kp2, 1) / 3 : Math::infinity();
269  } else {
270  _kKc = _eEc = Math::pi()/2; _dDc = _kKc/2;
271  }
272  if (_alpha2 != 0) {
273  // https://dlmf.nist.gov/19.25.E2
274  real rj = (_kp2 != 0 && _alphap2 != 0) ? RJ(0, _kp2, 1, _alphap2) :
275  Math::infinity(),
276  // Only use rc if _kp2 = 0.
277  rc = _kp2 != 0 ? 0 :
278  (_alphap2 != 0 ? RC(1, _alphap2) : Math::infinity());
279  // Pi(alpha^2, k)
280  _pPic = _kp2 != 0 ? _kKc + _alpha2 * rj / 3 : Math::infinity();
281  // G(alpha^2, k)
282  _gGc = _kp2 != 0 ? _kKc + (_alpha2 - _k2) * rj / 3 : rc;
283  // H(alpha^2, k)
284  _hHc = _kp2 != 0 ? _kKc - (_alphap2 != 0 ? _alphap2 * rj : 0) / 3 : rc;
285  } else {
286  _pPic = _kKc; _gGc = _eEc;
287  // Hc = Kc - Dc but this involves large cancellations if k2 is close to
288  // 1. So write (for alpha2 = 0)
289  // Hc = int(cos(phi)^2/sqrt(1-k2*sin(phi)^2),phi,0,pi/2)
290  // = 1/sqrt(1-k2) * int(sin(phi)^2/sqrt(1-k2/kp2*sin(phi)^2,...)
291  // = 1/kp * D(i*k/kp)
292  // and use D(k) = RD(0, kp2, 1) / 3
293  // so Hc = 1/kp * RD(0, 1/kp2, 1) / 3
294  // = kp2 * RD(0, 1, kp2) / 3
295  // using https://dlmf.nist.gov/19.20.E18
296  // Equivalently
297  // RF(x, 1) - RD(0, x, 1)/3 = x * RD(0, 1, x)/3 for x > 0
298  // For k2 = 0 and alpha2 = 0, we have
299  // Hc = int(cos(phi)^2,...) = pi/4
300  // For k2 = 1 and alpha2 = 0, we have
301  // Hc = int(cos(phi),...) = 1
302  _hHc = _kp2 == 1 ? Math::pi()/4 :
303  (_kp2 == 0 ? 1 : _kp2 * RD(0, 1, _kp2) / 3);
304  }
305  }
306 
307  /*
308  * Implementation of methods given in
309  *
310  * R. Bulirsch
311  * Numerical Calculation of Elliptic Integrals and Elliptic Functions
312  * Numericshe Mathematik 7, 78-90 (1965)
313  */
314 
315  void EllipticFunction::sncndn(real x, real& sn, real& cn, real& dn) const {
316  // Bulirsch's sncndn routine, p 89.
317  static const real tolJAC =
318  sqrt(numeric_limits<real>::epsilon() * real(0.01));
319  if (_kp2 != 0) {
320  real mc = _kp2, d = 0;
321  if (signbit(_kp2)) {
322  // This implements DLMF Eqs 22.17.2 - 22.17.4. But this only
323  // accomodates kp2 < 0 or k2 > 1 and these are outside the advertized
324  // ranges for the contructor for this class.
325  d = 1 - mc;
326  mc /= -d;
327  d = sqrt(d);
328  x *= d;
329  }
330  real c = 0; // To suppress warning about uninitialized variable
331  real m[num_], n[num_];
332  unsigned l = 0;
333  for (real a = 1;
334  l < num_ ||
336  ("Convergence failure in EllipticFunction::sncndn");
337  ++l) {
338  // This converges quadratically. Max 5 trips
339  m[l] = a;
340  n[l] = mc = sqrt(mc);
341  c = (a + mc) / 2;
342  if (!(fabs(a - mc) > tolJAC * a)) {
343  ++l;
344  break;
345  }
346  mc *= a;
347  a = c;
348  }
349  x *= c;
350  sn = sin(x);
351  cn = cos(x);
352  dn = 1;
353  if (sn != 0) {
354  real a = cn / sn;
355  c *= a;
356  while (l--) {
357  real b = m[l];
358  a *= c;
359  c *= dn;
360  dn = (n[l] + a) / (b + a);
361  a = c / b;
362  }
363  a = 1 / sqrt(c*c + 1);
364  sn = signbit(sn) ? -a : a;
365  cn = c * sn;
366  if (signbit(_kp2)) {
367  // See DLMF Eqs 22.17.2 - 22.17.4
368  swap(cn, dn);
369  sn /= d;
370  }
371  }
372  } else {
373  sn = tanh(x);
374  dn = cn = 1 / cosh(x);
375  }
376  }
377 
379  // This implements DLMF Sec 22.20(ii).
380  // See also Sala (1989), https://doi.org/10.1137/0520100, Sec 5.
381  static const real tolJAC =
382  pow(numeric_limits<real>::epsilon(), real(0.75));
383  real k2 = _k2, kp2 = _kp2;
384  if (_k2 == 0)
385  return x;
386  else if (_kp2 == 0) {
387  return atan(sinh(x)); // gd(x)
388  } else if (_k2 < 0) {
389  // Sala Eq. 5.8
390  k2 = -_k2 / _kp2; kp2 = 1 / _kp2;
391  x *= sqrt(_kp2);
392  }
393  real a[num_], b, c[num_];
394  a[0] = 1; b = sqrt(kp2); c[0] = sqrt(k2);
395  int l = 1;
396  for (; l < num_ ||
398  ("Convergence failure in EllipticFunction::am");) {
399  a[l] = (a[l-1] + b) / 2;
400  c[l] = (a[l-1] - b) / 2;
401  b = sqrt(a[l-1] * b);
402  if (!(c[l] > tolJAC * a[l])) break;
403  ++l;
404  }
405  // Now a[l] = pi/(2*K)
406  // Need to initialize phi1 to stop Visual Studio complaining
407  real phi = a[l] * x * real(1 << l), phi1 = 0;
408  for (; l > 0; --l) {
409  phi1 = phi;
410  phi = (phi + asin(c[l] * sin(phi) / a[l])) / 2;
411  }
412  // For k2 < 0, see Sala Eq. 5.8
413  return _k2 < 0 ? phi1 - phi : phi;
414  }
415 
416  Math::real EllipticFunction::am(real x, real& sn, real& cn, real& dn) const {
417  real phi = am(x);
418  if (_kp2 == 0) {
419  // Could rely on sin(gd(x)) = tanh(x) and cos(gd(x)) = 1 / cosh(x). But
420  // this is more accurate for large |x|.
421  sn = tanh(x); cn = dn = 1 / cosh(x);
422  } else {
423  sn = sin(phi); cn = cos(phi);
424  // See comment following DLMF Eq. 22.20.5
425  // dn = cn / cos(phi1 - phi)
426  dn = Delta(sn, cn);
427  }
428  return phi;
429  }
430 
431  Math::real EllipticFunction::F(real sn, real cn, real dn) const {
432  // Carlson, eq. 4.5 and
433  // https://dlmf.nist.gov/19.25.E5
434  real cn2 = cn*cn, dn2 = dn*dn,
435  fi = cn2 != 0 ? fabs(sn) * RF(cn2, dn2, 1) : K();
436  // Enforce usual trig-like symmetries
437  if (signbit(cn))
438  fi = 2 * K() - fi;
439  return copysign(fi, sn);
440  }
441 
442  Math::real EllipticFunction::E(real sn, real cn, real dn) const {
443  real
444  cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
445  ei = cn2 != 0 ?
446  fabs(sn) * ( _k2 <= 0 ?
447  // Carlson, eq. 4.6 and
448  // https://dlmf.nist.gov/19.25.E9
449  RF(cn2, dn2, 1) - _k2 * sn2 * RD(cn2, dn2, 1) / 3 :
450  ( _kp2 >= 0 ?
451  // https://dlmf.nist.gov/19.25.E10
452  _kp2 * RF(cn2, dn2, 1) +
453  _k2 * _kp2 * sn2 * RD(cn2, 1, dn2) / 3 +
454  _k2 * fabs(cn) / dn :
455  // https://dlmf.nist.gov/19.25.E11
456  - _kp2 * sn2 * RD(dn2, 1, cn2) / 3 +
457  dn / fabs(cn) ) ) :
458  E();
459  // Enforce usual trig-like symmetries
460  if (signbit(cn))
461  ei = 2 * E() - ei;
462  return copysign(ei, sn);
463  }
464 
465  Math::real EllipticFunction::D(real sn, real cn, real dn) const {
466  // Carlson, eq. 4.8 and
467  // https://dlmf.nist.gov/19.25.E13
468  real
469  cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
470  di = cn2 != 0 ? fabs(sn) * sn2 * RD(cn2, dn2, 1) / 3 : D();
471  // Enforce usual trig-like symmetries
472  if (signbit(cn))
473  di = 2 * D() - di;
474  return copysign(di, sn);
475  }
476 
477  Math::real EllipticFunction::Pi(real sn, real cn, real dn) const {
478  // Carlson, eq. 4.7 and
479  // https://dlmf.nist.gov/19.25.E14
480  real
481  cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
482  pii = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) +
483  _alpha2 * sn2 *
484  RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) :
485  Pi();
486  // Enforce usual trig-like symmetries
487  if (signbit(cn))
488  pii = 2 * Pi() - pii;
489  return copysign(pii, sn);
490  }
491 
492  Math::real EllipticFunction::G(real sn, real cn, real dn) const {
493  real
494  cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
495  gi = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) +
496  (_alpha2 - _k2) * sn2 *
497  RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) :
498  G();
499  // Enforce usual trig-like symmetries
500  if (signbit(cn))
501  gi = 2 * G() - gi;
502  return copysign(gi, sn);
503  }
504 
505  Math::real EllipticFunction::H(real sn, real cn, real dn) const {
506  real
507  cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
508  // WARNING: large cancellation if k2 = 1, alpha2 = 0, and phi near pi/2
509  hi = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) -
510  _alphap2 * sn2 *
511  RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) :
512  H();
513  // Enforce usual trig-like symmetries
514  if (signbit(cn))
515  hi = 2 * H() - hi;
516  return copysign(hi, sn);
517  }
518 
519  Math::real EllipticFunction::deltaF(real sn, real cn, real dn) const {
520  // Function is periodic with period pi
521  if (signbit(cn)) { cn = -cn; sn = -sn; }
522  return F(sn, cn, dn) * (Math::pi()/2) / K() - atan2(sn, cn);
523  }
524 
525  Math::real EllipticFunction::deltaE(real sn, real cn, real dn) const {
526  // Function is periodic with period pi
527  if (signbit(cn)) { cn = -cn; sn = -sn; }
528  return E(sn, cn, dn) * (Math::pi()/2) / E() - atan2(sn, cn);
529  }
530 
531  Math::real EllipticFunction::deltaPi(real sn, real cn, real dn) const {
532  // Function is periodic with period pi
533  if (signbit(cn)) { cn = -cn; sn = -sn; }
534  return Pi(sn, cn, dn) * (Math::pi()/2) / Pi() - atan2(sn, cn);
535  }
536 
537  Math::real EllipticFunction::deltaD(real sn, real cn, real dn) const {
538  // Function is periodic with period pi
539  if (signbit(cn)) { cn = -cn; sn = -sn; }
540  return D(sn, cn, dn) * (Math::pi()/2) / D() - atan2(sn, cn);
541  }
542 
543  Math::real EllipticFunction::deltaG(real sn, real cn, real dn) const {
544  // Function is periodic with period pi
545  if (signbit(cn)) { cn = -cn; sn = -sn; }
546  return G(sn, cn, dn) * (Math::pi()/2) / G() - atan2(sn, cn);
547  }
548 
549  Math::real EllipticFunction::deltaH(real sn, real cn, real dn) const {
550  // Function is periodic with period pi
551  if (signbit(cn)) { cn = -cn; sn = -sn; }
552  return H(sn, cn, dn) * (Math::pi()/2) / H() - atan2(sn, cn);
553  }
554 
555  Math::real EllipticFunction::F(real phi) const {
556  if (_k2 == 0)
557  return phi;
558  else if (_kp2 == 0)
559  return asinh(tan(phi));
560  real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
561  return fabs(phi) < Math::pi() ? F(sn, cn, dn) :
562  (deltaF(sn, cn, dn) + phi) * K() / (Math::pi()/2);
563  }
564 
565  Math::real EllipticFunction::E(real phi) const {
566  if (_k2 == 0)
567  return phi;
568  // else if (_kp2 == 0)
569  // Despite DLMF Eq 19.6.9 this is probably wrong, since
570  // sqrt(1 - k^2*sin(phi)^2) -> abs(cos(phi)) in the limit k -> 1.
571  // return sin(phi);
572  real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
573  return fabs(phi) < Math::pi() ? E(sn, cn, dn) :
574  (deltaE(sn, cn, dn) + phi) * E() / (Math::pi()/2);
575  }
576 
578  // ang - Math::AngNormalize(ang) is (nearly) an exact multiple of 360
579  real n = round((ang - Math::AngNormalize(ang))/Math::td);
580  real sn, cn;
581  Math::sincosd(ang, sn, cn);
582  return E(sn, cn, Delta(sn, cn)) + 4 * E() * n;
583  }
584 
586  real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
587  return fabs(phi) < Math::pi() ? Pi(sn, cn, dn) :
588  (deltaPi(sn, cn, dn) + phi) * Pi() / (Math::pi()/2);
589  }
590 
591  Math::real EllipticFunction::D(real phi) const {
592  real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
593  return fabs(phi) < Math::pi() ? D(sn, cn, dn) :
594  (deltaD(sn, cn, dn) + phi) * D() / (Math::pi()/2);
595  }
596 
597  Math::real EllipticFunction::G(real phi) const {
598  real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
599  return fabs(phi) < Math::pi() ? G(sn, cn, dn) :
600  (deltaG(sn, cn, dn) + phi) * G() / (Math::pi()/2);
601  }
602 
603  Math::real EllipticFunction::H(real phi) const {
604  real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
605  return fabs(phi) < Math::pi() ? H(sn, cn, dn) :
606  (deltaH(sn, cn, dn) + phi) * H() / (Math::pi()/2);
607  }
608 
610  static const real tolJAC =
611  sqrt(numeric_limits<real>::epsilon() / real(100));
612  real n = floor(x / (2 * _eEc) + real(0.5));
613  x -= 2 * _eEc * n; // x now in [-ec, ec)
614  // Linear approximation
615  real phi = Math::pi() * x / (2 * _eEc); // phi in [-pi/2, pi/2)
616  // First order correction
617  phi -= _eps * sin(2 * phi) / 2;
618  // For kp2 close to zero use asin(x/_eEc) or
619  // J. P. Boyd, Applied Math. and Computation 218, 7005-7013 (2012)
620  // https://doi.org/10.1016/j.amc.2011.12.021
621  for (int i = 0;
622  i < num_ ||
623  GEOGRAPHICLIB_PANIC("Convergence failure in EllipticFunction::Einv");
624  ++i) {
625  real
626  sn = sin(phi),
627  cn = cos(phi),
628  dn = Delta(sn, cn),
629  err = (E(sn, cn, dn) - x)/dn;
630  phi -= err;
631  if (!(fabs(err) > tolJAC))
632  break;
633  }
634  return n * Math::pi() + phi;
635  }
636 
637  Math::real EllipticFunction::deltaEinv(real stau, real ctau) const {
638  // Function is periodic with period pi
639  if (signbit(ctau)) { ctau = -ctau; stau = -stau; }
640  real tau = atan2(stau, ctau);
641  return Einv( tau * E() / (Math::pi()/2) ) - tau;
642  }
643 
644 } // namespace GeographicLib
static T pi()
Definition: Math.hpp:187
void sncndn(real x, real &sn, real &cn, real &dn) const
void Reset(real k2=0, real alpha2=0)
static T infinity()
Definition: Math.cpp:308
Math::real deltaPi(real sn, real cn, real dn) const
Math::real deltaE(real sn, real cn, real dn) const
static real RG(real x, real y, real z)
static T AngNormalize(T x)
Definition: Math.cpp:69
static T sq(T x)
Definition: Math.hpp:209
static real RF(real x, real y, real z)
static real RC(real x, real y)
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
Header for GeographicLib::EllipticFunction class.
Math::real F(real phi) const
Math::real deltaH(real sn, real cn, real dn) const
GeographicLib::Math::real real
Definition: Geod3Solve.cpp:25
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)
Math::real deltaG(real sn, real cn, real dn) const
Math::real Ed(real ang) const
Math::real Einv(real x) const
#define GEOGRAPHICLIB_PANIC(msg)
Definition: Math.hpp:67
Exception handling for GeographicLib.
Definition: Constants.hpp:344
Math::real deltaD(real sn, real cn, real dn) const
static real RD(real x, real y, real z)
static void sincosd(T x, T &sinx, T &cosx)
Definition: Math.cpp:104
Math::real deltaEinv(real stau, real ctau) const
static real RJ(real x, real y, real z, real p)
static constexpr int td
degrees per turn
Definition: Math.hpp:146
Math::real deltaF(real sn, real cn, real dn) const