GeographicLib 2.6
Loading...
Searching...
No Matches
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
70namespace 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 **********************************************************************/
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
Header for GeographicLib::Constants class.
#define GEOGRAPHICLIB_EXPORT
Definition Constants.hpp:59
#define GEOGRAPHICLIB_WORDS_BIGENDIAN
Definition Math.hpp:18
static T degree()
Definition Math.hpp:197
static constexpr int dm
minutes per degree
Definition Math.hpp:143
static T LatFix(T x)
Definition Math.hpp:303
static constexpr int ds
seconds per degree
Definition Math.hpp:147
static void norm(T &x, T &y)
Definition Math.hpp:219
static T sq(T x)
Definition Math.hpp:209
static constexpr int qd
degrees per quarter turn
Definition Math.hpp:142
static int digits10()
Definition Math.cpp:41
static int digits()
Definition Math.cpp:20
static const bool bigendian
Definition Math.hpp:181
static constexpr int td
degrees per turn
Definition Math.hpp:146
static T pi()
Definition Math.hpp:187
static T NaN()
Definition Math.cpp:301
static T polyval(int N, const T p[], T x)
Definition Math.hpp:270
static T AngDiff(T x, T y, T &e)
Definition Math.cpp:80
static constexpr int hd
degrees per half turn
Definition Math.hpp:145
static T AngDiff(T x, T y)
Definition Math.hpp:337
static int set_digits(int ndigits)
Definition Math.cpp:28
static T swab(T x)
Definition Math.hpp:547
static constexpr int ms
seconds per minute
Definition Math.hpp:144
static int extra_digits()
Definition Math.cpp:49
Namespace for GeographicLib.
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)