GeographicLib  2.6
Math.hpp
Go to the documentation of this file.
1 /**
2  * \file Math.hpp
3  * \brief Header for GeographicLib::Math 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 
10 // Constants.hpp includes Math.hpp. Place this include outside Math.hpp's
11 // include guard to enforce this ordering.
13 
14 #if !defined(GEOGRAPHICLIB_MATH_HPP)
15 #define GEOGRAPHICLIB_MATH_HPP 1
16 
17 #if !defined(GEOGRAPHICLIB_WORDS_BIGENDIAN)
18 # define GEOGRAPHICLIB_WORDS_BIGENDIAN 0
19 #endif
20 
21 #if !defined(GEOGRAPHICLIB_HAVE_LONG_DOUBLE)
22 # define GEOGRAPHICLIB_HAVE_LONG_DOUBLE 0
23 #endif
24 
25 #if !defined(GEOGRAPHICLIB_PRECISION)
26 /**
27  * The precision of floating point numbers used in %GeographicLib. 1 means
28  * float (single precision); 2 (the default) means double; 3 means long double;
29  * 4 is reserved for quadruple precision. Nearly all the testing has been
30  * carried out with doubles and that's the recommended configuration. In order
31  * for long double to be used, GEOGRAPHICLIB_HAVE_LONG_DOUBLE needs to be
32  * defined. Note that with Microsoft Visual Studio, long double is the same as
33  * double.
34  **********************************************************************/
35 # define GEOGRAPHICLIB_PRECISION 2
36 #endif
37 
38 #include <cmath>
39 #include <algorithm>
40 #include <limits>
41 
42 #if GEOGRAPHICLIB_PRECISION == 4
43 # include <memory>
44 # include <boost/version.hpp>
45 # include <boost/multiprecision/float128.hpp>
46 # include <boost/math/special_functions.hpp>
47 #elif GEOGRAPHICLIB_PRECISION >= 5
48 # if GEOGRAPHICLIB_PRECISION > 5
49 # define MPREAL_FIXED_PRECISION GEOGRAPHICLIB_PRECISION
50 # else
51 # define MPREAL_FIXED_PRECISION 0
52 # endif
53 # include <mpreal.h>
54 #endif
55 
56 #if GEOGRAPHICLIB_PRECISION > 3
57 // volatile keyword makes no sense for multiprec types
58 # define GEOGRAPHICLIB_VOLATILE
59 // Signal a convergence failure with multiprec types by throwing an exception
60 // at loop exit.
61 # define GEOGRAPHICLIB_PANIC(msg) \
62  (throw GeographicLib::GeographicErr(msg), false)
63 #else
64 # define GEOGRAPHICLIB_VOLATILE volatile
65 // Ignore convergence failures with standard floating points types by allowing
66 // loop to exit cleanly.
67 # define GEOGRAPHICLIB_PANIC(msg) false
68 #endif
69 
70 namespace GeographicLib {
71 
72  /**
73  * \brief Mathematical functions needed by %GeographicLib
74  *
75  * Define mathematical functions in order to localize system dependencies and
76  * to provide generic versions of the functions. In addition define a real
77  * type to be used by %GeographicLib.
78  *
79  * Example of use:
80  * \include example-Math.cpp
81  **********************************************************************/
83  private:
84  void dummy(); // Static check for GEOGRAPHICLIB_PRECISION
85  Math() = delete; // Disable constructor
86  public:
87 
88 #if GEOGRAPHICLIB_HAVE_LONG_DOUBLE
89  /**
90  * The extended precision type for real numbers, used for some testing.
91  * This is long double on computers with this type; otherwise it is double.
92  **********************************************************************/
93  typedef long double extended;
94 #else
95  typedef double extended;
96 #endif
97 
98 #if GEOGRAPHICLIB_PRECISION == 2
99  /**
100  * The real type for %GeographicLib. Nearly all the testing has been done
101  * with \e real = double. However, the algorithms should also work with
102  * float and long double (where available). (<b>CAUTION</b>: reasonable
103  * accuracy typically cannot be obtained using floats.)
104  **********************************************************************/
105  typedef double real;
106 #elif GEOGRAPHICLIB_PRECISION == 1
107  typedef float real;
108 #elif GEOGRAPHICLIB_PRECISION == 3
109  typedef extended real;
110 #elif GEOGRAPHICLIB_PRECISION == 4
111  typedef boost::multiprecision::float128 real;
112 #elif GEOGRAPHICLIB_PRECISION >= 5
113  typedef mpfr::mpreal real;
114 #else
115  typedef double real;
116 #endif
117 
118  /**
119  * The constants defining the standard (Babylonian) meanings of degrees,
120  * minutes, and seconds, for angles. Read the constants as follows (for
121  * example): \e ms = 60 is the ratio 1 minute / 1 second. The
122  * abbreviations are
123  * - \e t a whole turn (360&deg;)
124  * - \e h a half turn (180&deg;)
125  * - \e q a quarter turn (a right angle = 90&deg;)
126  * - \e d a degree
127  * - \e m a minute
128  * - \e s a second
129  * .
130  * Note that degree() is ratio 1 degree / 1 radian, thus, for example,
131  * Math::degree() * Math::qd is the ratio 1 quarter turn / 1 radian =
132  * &pi;/2.
133  *
134  * Defining all these in one place would mean that it's simple to convert
135  * to the centesimal system for measuring angles. The DMS class assumes
136  * that Math::dm and Math::ms are less than or equal to 100 (so that two
137  * digits suffice for the integer parts of the minutes and degrees
138  * components of an angle). Switching to the centesimal convention will
139  * break most of the tests. Also the normal definition of degree is baked
140  * into some classes, e.g., UTMUPS, MGRS, Georef, Geohash, etc.
141  **********************************************************************/
142  static inline constexpr int qd = 90; ///< degrees per quarter turn
143  static inline constexpr int dm = 60; ///< minutes per degree
144  static inline constexpr int ms = 60; ///< seconds per minute
145  static inline constexpr int hd = 2 * qd; ///< degrees per half turn
146  static inline constexpr int td = 2 * hd; ///< degrees per turn
147  static inline constexpr int ds = dm * ms; ///< seconds per degree
148 
149  /**
150  * @return the number of bits of precision in a real number.
151  **********************************************************************/
152  static int digits();
153 
154  /**
155  * Set the binary precision of a real number.
156  *
157  * @param[in] ndigits the number of bits of precision.
158  * @return the resulting number of bits of precision.
159  *
160  * This only has an effect when GEOGRAPHICLIB_PRECISION >= 5. See also
161  * Utility::set_digits for caveats about when this routine should be
162  * called. If GEOGRAPHICLIB_PRECISION > 5, the precision is set to the
163  * compile-time value of GEOGRAPHICLIB_PRECISION and \e ndigits is ignored.
164  **********************************************************************/
165  static int set_digits(int ndigits);
166 
167  /**
168  * @return the number of decimal digits of precision in a real number.
169  **********************************************************************/
170  static int digits10();
171 
172  /**
173  * Number of additional decimal digits of precision for real relative to
174  * double (0 for float).
175  **********************************************************************/
176  static int extra_digits();
177 
178  /**
179  * true if the machine is big-endian.
180  **********************************************************************/
181  static const bool bigendian = GEOGRAPHICLIB_WORDS_BIGENDIAN;
182 
183  /**
184  * @tparam T the type of the returned value.
185  * @return &pi;.
186  **********************************************************************/
187  template<typename T = real> static T pi() {
188  using std::atan2;
189  static const T pi = atan2(T(0), T(-1));
190  return pi;
191  }
192 
193  /**
194  * @tparam T the type of the returned value.
195  * @return the number of radians in a degree.
196  **********************************************************************/
197  template<typename T = real> static T degree() {
198  static const T degree = pi<T>() / T(hd);
199  return degree;
200  }
201 
202  /**
203  * Square a number.
204  *
205  * @tparam T the type of the argument and the returned value.
206  * @param[in] x
207  * @return <i>x</i><sup>2</sup>.
208  **********************************************************************/
209  template<typename T> static T sq(T x)
210  { return x * x; }
211 
212  /**
213  * Normalize a two-vector.
214  *
215  * @tparam T the type of the argument and the returned value.
216  * @param[in,out] x on output set to <i>x</i>/hypot(<i>x</i>, <i>y</i>).
217  * @param[in,out] y on output set to <i>y</i>/hypot(<i>x</i>, <i>y</i>).
218  **********************************************************************/
219  template<typename T> static void norm(T& x, T& y) {
220 #if defined(_MSC_VER) && _MSC_VER < 1950 && defined(_M_IX86)
221  // hypot for Visual Studio (A=win32) fails monotonicity, e.g., with
222  // x = 0.6102683302836215
223  // y1 = 0.7906090004346522
224  // y2 = y1 + 1e-16
225  // the test
226  // hypot(x, y2) >= hypot(x, y1)
227  // fails. Reported 2021-03-14:
228  // https://developercommunity.visualstudio.com/t/1369259
229  // See also:
230  // https://bugs.python.org/issue43088
231  // Bug still present in my version of vc17 (2022) updated on 2025-09-01.
232  // Let's hope it's fixed in vc18.
233  using std::sqrt; T h = sqrt(x * x + y * y);
234 #else
235  using std::hypot; T h = hypot(x, y);
236 #endif
237  x /= h; y /= h;
238  }
239 
240  /**
241  * The error-free sum of two numbers.
242  *
243  * @tparam T the type of the argument and the returned value.
244  * @param[in] u
245  * @param[in] v
246  * @param[out] t the exact error given by (\e u + \e v) - \e s.
247  * @return \e s = round(\e u + \e v).
248  *
249  * See D. E. Knuth, TAOCP, Vol 2, 4.2.2, Theorem B.
250  *
251  * \note \e t can be the same as one of the first two arguments.
252  **********************************************************************/
253  template<typename T> static T sum(T u, T v, T& t);
254 
255  /**
256  * Evaluate a polynomial.
257  *
258  * @tparam T the type of the arguments and returned value.
259  * @param[in] N the order of the polynomial.
260  * @param[in] p the coefficient array (of size \e N + 1) with
261  * <i>p</i><sub>0</sub> being coefficient of <i>x</i><sup><i>N</i></sup>.
262  * @param[in] x the variable.
263  * @return the value of the polynomial.
264  *
265  * Evaluate &sum;<sub><i>n</i>=0..<i>N</i></sub>
266  * <i>p</i><sub><i>n</i></sub> <i>x</i><sup><i>N</i>&minus;<i>n</i></sup>.
267  * Return 0 if \e N &lt; 0. Return <i>p</i><sub>0</sub>, if \e N = 0 (even
268  * if \e x is infinite or a nan). The evaluation uses Horner's method.
269  **********************************************************************/
270  template<typename T> static T polyval(int N, const T p[], T x) {
271  // This used to employ Math::fma; but that's too slow and it seemed not
272  // to improve the accuracy noticeably. This might change when there's
273  // direct hardware support for fma.
274  T z = N < 0 ? 0 : *p++;
275  while (--N >= 0) z = z * x + *p++;
276  // To compute z = p(x) and dz = (p(y)-p(x))/(y-x) at the same time
277  // See Kahan + Fateman Sec 2.3. If y = x, dz = p'(x)
278  // T z = N < 0 ? 0 : *p++, dz = 0;
279  // while (--N >= 0) { dz = dz * y + p; z = z * x + *p++; }
280  return z;
281  }
282 
283  /**
284  * Normalize an angle.
285  *
286  * @tparam T the type of the argument and returned value.
287  * @param[in] x the angle in degrees.
288  * @return the angle reduced to the range [&minus;180&deg;, 180&deg;].
289  *
290  * The range of \e x is unrestricted. If the result is &plusmn;0&deg; or
291  * &plusmn;180&deg; then the sign is the sign of \e x.
292  **********************************************************************/
293  template<typename T> static T AngNormalize(T x);
294 
295  /**
296  * Normalize a latitude.
297  *
298  * @tparam T the type of the argument and returned value.
299  * @param[in] x the angle in degrees.
300  * @return x if it is in the range [&minus;90&deg;, 90&deg;], otherwise
301  * return NaN.
302  **********************************************************************/
303  template<typename T> static T LatFix(T x)
304  { using std::fabs; return fabs(x) > T(qd) ? NaN<T>() : x; }
305 
306  /**
307  * The exact difference of two angles reduced to
308  * [&minus;180&deg;, 180&deg;].
309  *
310  * @tparam T the type of the arguments and returned value.
311  * @param[in] x the first angle in degrees.
312  * @param[in] y the second angle in degrees.
313  * @param[out] e the error term in degrees.
314  * @return \e d, the truncated value of \e y &minus; \e x.
315  *
316  * This computes \e z = \e y &minus; \e x exactly, reduced to
317  * [&minus;180&deg;, 180&deg;]; and then sets \e z = \e d + \e e where \e d
318  * is the nearest representable number to \e z and \e e is the truncation
319  * error. If \e z = &plusmn;0&deg; or &plusmn;180&deg;, then the sign of
320  * \e d is given by the sign of \e y &minus; \e x. The maximum absolute
321  * value of \e e is 2<sup>&minus;26</sup> (for doubles).
322  **********************************************************************/
323  template<typename T> static T AngDiff(T x, T y, T& e);
324 
325  /**
326  * Difference of two angles reduced to [&minus;180&deg;, 180&deg;]
327  *
328  * @tparam T the type of the arguments and returned value.
329  * @param[in] x the first angle in degrees.
330  * @param[in] y the second angle in degrees.
331  * @return \e y &minus; \e x, reduced to the range [&minus;180&deg;,
332  * 180&deg;].
333  *
334  * The result is equivalent to computing the difference exactly, reducing
335  * it to [&minus;180&deg;, 180&deg;] and rounding the result.
336  **********************************************************************/
337  template<typename T> static T AngDiff(T x, T y)
338  { T e; return AngDiff(x, y, e); }
339 
340  /**
341  * Coarsen a value close to zero.
342  *
343  * @tparam T the type of the argument and returned value.
344  * @param[in] x
345  * @return the coarsened value.
346  *
347  * The makes the smallest gap in \e x = 1/16 &minus; nextafter(1/16, 0) =
348  * 1/2<sup>57</sup> for doubles = 0.8 pm on the earth if \e x is an angle
349  * in degrees. (This is about 2000 times more resolution than we get with
350  * angles around 90&deg;.) We use this to avoid having to deal with near
351  * singular cases when \e x is non-zero but tiny (e.g.,
352  * 10<sup>&minus;200</sup>). This sign of &plusmn;0 is preserved.
353  **********************************************************************/
354  template<typename T> static T AngRound(T x);
355 
356  /**
357  * Evaluate the sine and cosine function with the argument in degrees
358  *
359  * @tparam T the type of the arguments.
360  * @param[in] x in degrees.
361  * @param[out] sinx sin(<i>x</i>).
362  * @param[out] cosx cos(<i>x</i>).
363  *
364  * The results obey exactly the elementary properties of the trigonometric
365  * functions, e.g., sin 9&deg; = cos 81&deg; = &minus; sin 123456789&deg;.
366  * If x = &minus;0 or a negative multiple of 180&deg;, then \e sinx =
367  * &minus;0; this is the only case where &minus;0 is returned.
368  **********************************************************************/
369  template<typename T> static void sincosd(T x, T& sinx, T& cosx);
370 
371  /**
372  * Evaluate the sine and cosine with reduced argument plus correction
373  *
374  * @tparam T the type of the arguments.
375  * @param[in] x reduced angle in degrees.
376  * @param[in] t correction in degrees.
377  * @param[out] sinx sin(<i>x</i> + <i>t</i>).
378  * @param[out] cosx cos(<i>x</i> + <i>t</i>).
379  *
380  * This is a variant of Math::sincosd allowing a correction to the angle to
381  * be supplied. \e x must be in [&minus;180&deg;, 180&deg;] and \e t is
382  * assumed to be a <i>small</i> correction. Math::AngRound is applied to
383  * the reduced angle to prevent problems with \e x + \e t being extremely
384  * close but not exactly equal to one of the four cardinal directions.
385  **********************************************************************/
386  template<typename T> static void sincosde(T x, T t, T& sinx, T& cosx);
387 
388  /**
389  * Evaluate the sine function with the argument in degrees
390  *
391  * @tparam T the type of the argument and the returned value.
392  * @param[in] x in degrees.
393  * @return sin(<i>x</i>).
394  *
395  * The result is +0 for \e x = +0 and positive multiples of 180&deg;. The
396  * result is &minus;0 for \e x = -0 and negative multiples of 180&deg;.
397  **********************************************************************/
398  template<typename T> static T sind(T x);
399 
400  /**
401  * Evaluate the cosine function with the argument in degrees
402  *
403  * @tparam T the type of the argument and the returned value.
404  * @param[in] x in degrees.
405  * @return cos(<i>x</i>).
406  *
407  * The result is +0 for \e x an odd multiple of 90&deg;.
408  **********************************************************************/
409  template<typename T> static T cosd(T x);
410 
411  /**
412  * Evaluate the tangent function with the argument in degrees
413  *
414  * @tparam T the type of the argument and the returned value.
415  * @param[in] x in degrees.
416  * @return tan(<i>x</i>).
417  *
418  * If \e x is an odd multiple of 90&deg;, then a suitably large (but
419  * finite) value is returned.
420  **********************************************************************/
421  template<typename T> static T tand(T x);
422 
423  /**
424  * Evaluate the atan2 function with the result in degrees
425  *
426  * @tparam T the type of the arguments and the returned value.
427  * @param[in] y
428  * @param[in] x
429  * @return atan2(<i>y</i>, <i>x</i>) in degrees.
430  *
431  * The result is in the range [&minus;180&deg; 180&deg;]. N.B.,
432  * atan2d(&plusmn;0, &minus;1) = &plusmn;180&deg;.
433  **********************************************************************/
434  template<typename T> static T atan2d(T y, T x);
435 
436  /**
437  * Evaluate the atan function with the result in degrees
438  *
439  * @tparam T the type of the argument and the returned value.
440  * @param[in] x
441  * @return atan(<i>x</i>) in degrees.
442  **********************************************************************/
443  template<typename T> static T atand(T x);
444 
445  /**
446  * Evaluate <i>e</i> atanh(<i>e x</i>)
447  *
448  * @tparam T the type of the argument and the returned value.
449  * @param[in] x
450  * @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
451  * sqrt(|<i>e</i><sup>2</sup>|)
452  * @return <i>e</i> atanh(<i>e x</i>)
453  *
454  * If <i>e</i><sup>2</sup> is negative (<i>e</i> is imaginary), the
455  * expression is evaluated in terms of atan.
456  **********************************************************************/
457  template<typename T> static T eatanhe(T x, T es);
458 
459  /**
460  * tan&chi; in terms of tan&phi;
461  *
462  * @tparam T the type of the argument and the returned value.
463  * @param[in] tau &tau; = tan&phi;
464  * @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
465  * sqrt(|<i>e</i><sup>2</sup>|)
466  * @return &tau;&prime; = tan&chi;
467  *
468  * See Eqs. (7--9) of
469  * C. F. F. Karney,
470  * <a href="https://doi.org/10.1007/s00190-011-0445-3">
471  * Transverse Mercator with an accuracy of a few nanometers,</a>
472  * J. Geodesy 85(8), 475--485 (Aug. 2011)
473  * (preprint
474  * <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a>).
475  **********************************************************************/
476  template<typename T> static T taupf(T tau, T es);
477 
478  /**
479  * tan&phi; in terms of tan&chi;
480  *
481  * @tparam T the type of the argument and the returned value.
482  * @param[in] taup &tau;&prime; = tan&chi;
483  * @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
484  * sqrt(|<i>e</i><sup>2</sup>|)
485  * @return &tau; = tan&phi;
486  *
487  * See Eqs. (19--21) of
488  * C. F. F. Karney,
489  * <a href="https://doi.org/10.1007/s00190-011-0445-3">
490  * Transverse Mercator with an accuracy of a few nanometers,</a>
491  * J. Geodesy 85(8), 475--485 (Aug. 2011)
492  * (preprint
493  * <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a>).
494  **********************************************************************/
495  template<typename T> static T tauf(T taup, T es);
496 
497  /**
498  * Implement hypot with 3 parameters
499  *
500  * @tparam T the type of the argument and the returned value.
501  * @param[in] x
502  * @param[in] y
503  * @param[in] z
504  * @return sqrt(<i>x</i><sup>2</sup> + <i>y</i><sup>2</sup> +
505  * <i>z</i><sup>2</sup>).
506  **********************************************************************/
507  template<typename T> static T hypot3(T x, T y, T z);
508 
509  /**
510  * Implement work-alike to C++17 clamp function
511  *
512  * @tparam T the type of the argument and the returned value.
513  * @param[in] x
514  * @param[in] a
515  * @param[in] b
516  * @return \e x if it lies in [<i>a</i>, <i>b</i>]; otherise return the
517  * nearest boundary value.
518  *
519  * Requires \e a &le; \e b. Unlike std::clamp, \e x can be a NaN (and
520  * this is then returned).
521  **********************************************************************/
522  template<typename T> static T clamp(T x, T a, T b);
523 
524  /**
525  * The NaN (not a number)
526  *
527  * @tparam T the type of the returned value.
528  * @return NaN if available, otherwise return the max real of type T.
529  **********************************************************************/
530  template<typename T = real> static T NaN();
531 
532  /**
533  * Infinity
534  *
535  * @tparam T the type of the returned value.
536  * @return infinity if available, otherwise return the max real.
537  **********************************************************************/
538  template<typename T = real> static T infinity();
539 
540  /**
541  * Swap the bytes of a quantity
542  *
543  * @tparam T the type of the argument and the returned value.
544  * @param[in] x
545  * @return x with its bytes swapped.
546  **********************************************************************/
547  template<typename T> static T swab(T x) {
548  union {
549  T r;
550  unsigned char c[sizeof(T)];
551  } b;
552  b.r = x;
553  for (int i = sizeof(T)/2; i--; )
554  std::swap(b.c[i], b.c[sizeof(T) - 1 - i]);
555  return b.r;
556  }
557 
558  };
559 
560 } // namespace GeographicLib
561 
562 #endif // GEOGRAPHICLIB_MATH_HPP
static T pi()
Definition: Math.hpp:187
#define GEOGRAPHICLIB_EXPORT
Definition: Constants.hpp:59
#define GEOGRAPHICLIB_WORDS_BIGENDIAN
Definition: Math.hpp:18
static T LatFix(T x)
Definition: Math.hpp:303
Mathematical functions needed by GeographicLib.
Definition: Math.hpp:82
double extended
Definition: Math.hpp:95
static void norm(T &x, T &y)
Definition: Math.hpp:219
static T sq(T x)
Definition: Math.hpp:209
static T polyval(int N, const T p[], T x)
Definition: Math.hpp:270
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
static T degree()
Definition: Math.hpp:197
static T AngDiff(T x, T y)
Definition: Math.hpp:337
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)
static T swab(T x)
Definition: Math.hpp:547
Header for GeographicLib::Constants class.