GeographicLib  1.40
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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-2014) <charles@karney.com> and licensed
6  * under the MIT/X11 License. For more information, see
7  * http://geographiclib.sourceforge.net/
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 /**
18  * Are C++11 math functions available?
19  **********************************************************************/
20 #if !defined(GEOGRAPHICLIB_CXX11_MATH)
21 // Recent versions of g++ -std=c++11 (4.7 and later?) set __cplusplus to 201103
22 // and support the new C++11 mathematical functions, std::atanh, etc. However
23 // the Android toolchain, which uses g++ -std=c++11 (4.8 as of 2014-03-11,
24 // according to Pullan Lu), does not support std::atanh. Android toolchains
25 // might define __ANDROID__ or ANDROID; so need to check both. With OSX the
26 // version is GNUC version 4.2 and __cplusplus is set to 201103, so remove the
27 // version check on GNUC.
28 # if defined(__GNUC__) && __cplusplus >= 201103 && \
29  !(defined(__ANDROID__) || defined(ANDROID) || defined(__CYGWIN__))
30 # define GEOGRAPHICLIB_CXX11_MATH 1
31 // Visual C++ 12 supports these functions
32 # elif defined(_MSC_VER) && _MSC_VER >= 1800
33 # define GEOGRAPHICLIB_CXX11_MATH 1
34 # else
35 # define GEOGRAPHICLIB_CXX11_MATH 0
36 # endif
37 #endif
38 
39 #if !defined(GEOGRAPHICLIB_WORDS_BIGENDIAN)
40 # define GEOGRAPHICLIB_WORDS_BIGENDIAN 0
41 #endif
42 
43 #if !defined(GEOGRAPHICLIB_HAVE_LONG_DOUBLE)
44 # define GEOGRAPHICLIB_HAVE_LONG_DOUBLE 0
45 #endif
46 
47 #if !defined(GEOGRAPHICLIB_PRECISION)
48 /**
49  * The precision of floating point numbers used in %GeographicLib. 1 means
50  * float (single precision); 2 (the default) means double; 3 means long double;
51  * 4 is reserved for quadruple precision. Nearly all the testing has been
52  * carried out with doubles and that's the recommended configuration. In order
53  * for long double to be used, GEOGRAPHICLIB_HAVE_LONG_DOUBLE needs to be
54  * defined. Note that with Microsoft Visual Studio, long double is the same as
55  * double.
56  **********************************************************************/
57 # define GEOGRAPHICLIB_PRECISION 2
58 #endif
59 
60 #include <cmath>
61 #include <algorithm>
62 #include <limits>
63 
64 #if GEOGRAPHICLIB_PRECISION == 4
65 #include <boost/multiprecision/float128.hpp>
66 #include <boost/math/special_functions/hypot.hpp>
67 #include <boost/math/special_functions/expm1.hpp>
68 #include <boost/math/special_functions/log1p.hpp>
69 #include <boost/math/special_functions/atanh.hpp>
70 #include <boost/math/special_functions/asinh.hpp>
71 #include <boost/math/special_functions/cbrt.hpp>
72 #elif GEOGRAPHICLIB_PRECISION == 5
73 #include <mpreal.h>
74 #endif
75 
76 #if GEOGRAPHICLIB_PRECISION > 3
77 // volatile keyword makes no sense for multiprec types
78 #define GEOGRAPHICLIB_VOLATILE
79 // Signal a convergence failure with multiprec types by throwing an exception
80 // at loop exit.
81 #define GEOGRAPHICLIB_PANIC \
82  (throw GeographicLib::GeographicErr("Convergence failure"), false)
83 #else
84 #define GEOGRAPHICLIB_VOLATILE volatile
85 // Ignore convergence failures with standard floating points types by allowing
86 // loop to exit cleanly.
87 #define GEOGRAPHICLIB_PANIC false
88 #endif
89 
90 namespace GeographicLib {
91 
92  /**
93  * \brief Mathematical functions needed by %GeographicLib
94  *
95  * Define mathematical functions in order to localize system dependencies and
96  * to provide generic versions of the functions. In addition define a real
97  * type to be used by %GeographicLib.
98  *
99  * Example of use:
100  * \include example-Math.cpp
101  **********************************************************************/
103  private:
104  void dummy() {
105  GEOGRAPHICLIB_STATIC_ASSERT(GEOGRAPHICLIB_PRECISION >= 1 &&
107  "Bad value of precision");
108  }
109  Math(); // Disable constructor
110  public:
111 
112 #if GEOGRAPHICLIB_HAVE_LONG_DOUBLE
113  /**
114  * The extended precision type for real numbers, used for some testing.
115  * This is long double on computers with this type; otherwise it is double.
116  **********************************************************************/
117  typedef long double extended;
118 #else
119  typedef double extended;
120 #endif
121 
122 #if GEOGRAPHICLIB_PRECISION == 2
123  /**
124  * The real type for %GeographicLib. Nearly all the testing has been done
125  * with \e real = double. However, the algorithms should also work with
126  * float and long double (where available). (<b>CAUTION</b>: reasonable
127  * accuracy typically cannot be obtained using floats.)
128  **********************************************************************/
129  typedef double real;
130 #elif GEOGRAPHICLIB_PRECISION == 1
131  typedef float real;
132 #elif GEOGRAPHICLIB_PRECISION == 3
133  typedef extended real;
134 #elif GEOGRAPHICLIB_PRECISION == 4
135  typedef boost::multiprecision::float128 real;
136 #elif GEOGRAPHICLIB_PRECISION == 5
137  typedef mpfr::mpreal real;
138 #else
139  typedef double real;
140 #endif
141 
142  /**
143  * @return the number of bits of precision in a real number.
144  **********************************************************************/
145  static inline int digits() {
146 #if GEOGRAPHICLIB_PRECISION != 5
147  return std::numeric_limits<real>::digits;
148 #else
149  return std::numeric_limits<real>::digits();
150 #endif
151  }
152 
153  /**
154  * Set the binary precision of a real number.
155  *
156  * @param[in] ndigits the number of bits of precision.
157  * @return the resulting number of bits of precision.
158  *
159  * This only has an effect when GEOGRAPHICLIB_PRECISION == 5.
160  **********************************************************************/
161  static inline int set_digits(int ndigits) {
162 #if GEOGRAPHICLIB_PRECISION != 5
163  (void)ndigits;
164 #else
165  mpfr::mpreal::set_default_prec(ndigits >= 2 ? ndigits : 2);
166 #endif
167  return digits();
168  }
169 
170  /**
171  * @return the number of decimal digits of precision in a real number.
172  **********************************************************************/
173  static inline int digits10() {
174 #if GEOGRAPHICLIB_PRECISION != 5
175  return std::numeric_limits<real>::digits10;
176 #else
177  return std::numeric_limits<real>::digits10();
178 #endif
179  }
180 
181  /**
182  * Number of additional decimal digits of precision for real relative to
183  * double (0 for float).
184  **********************************************************************/
185  static inline int extra_digits() {
186  return
187  digits10() > std::numeric_limits<double>::digits10 ?
188  digits10() - std::numeric_limits<double>::digits10 : 0;
189  }
190 
191 #if GEOGRAPHICLIB_PRECISION <= 3
192  /**
193  * Number of additional decimal digits of precision of real relative to
194  * double (0 for float).
195  *
196  * <b>DEPRECATED</b>: use extra_digits() instead
197  **********************************************************************/
198  static const int extradigits =
199  std::numeric_limits<real>::digits10 >
200  std::numeric_limits<double>::digits10 ?
201  std::numeric_limits<real>::digits10 -
202  std::numeric_limits<double>::digits10 : 0;
203 #endif
204 
205  /**
206  * true if the machine is big-endian.
207  **********************************************************************/
208  static const bool bigendian = GEOGRAPHICLIB_WORDS_BIGENDIAN;
209 
210  /**
211  * @tparam T the type of the returned value.
212  * @return &pi;.
213  **********************************************************************/
214  template<typename T> static inline T pi() {
215  using std::atan2;
216  static const T pi = atan2(T(0), T(-1));
217  return pi;
218  }
219  /**
220  * A synonym for pi<real>().
221  **********************************************************************/
222  static inline real pi() { return pi<real>(); }
223 
224  /**
225  * @tparam T the type of the returned value.
226  * @return the number of radians in a degree.
227  **********************************************************************/
228  template<typename T> static inline T degree() {
229  static const T degree = pi<T>() / 180;
230  return degree;
231  }
232  /**
233  * A synonym for degree<real>().
234  **********************************************************************/
235  static inline real degree() { return degree<real>(); }
236 
237  /**
238  * Square a number.
239  *
240  * @tparam T the type of the argument and the returned value.
241  * @param[in] x
242  * @return <i>x</i><sup>2</sup>.
243  **********************************************************************/
244  template<typename T> static inline T sq(T x)
245  { return x * x; }
246 
247  /**
248  * The hypotenuse function avoiding underflow and overflow.
249  *
250  * @tparam T the type of the arguments and the returned value.
251  * @param[in] x
252  * @param[in] y
253  * @return sqrt(<i>x</i><sup>2</sup> + <i>y</i><sup>2</sup>).
254  **********************************************************************/
255  template<typename T> static inline T hypot(T x, T y) {
256 #if GEOGRAPHICLIB_CXX11_MATH
257  using std::hypot; return hypot(x, y);
258 #else
259  using std::abs; using std::sqrt;
260  x = abs(x); y = abs(y);
261  if (x < y) std::swap(x, y); // Now x >= y >= 0
262  y /= (x ? x : 1);
263  return x * sqrt(1 + y * y);
264  // For an alternative (square-root free) method see
265  // C. Moler and D. Morrision (1983) https://dx.doi.org/10.1147/rd.276.0577
266  // and A. A. Dubrulle (1983) https://dx.doi.org/10.1147/rd.276.0582
267 #endif
268  }
269 
270  /**
271  * exp(\e x) &minus; 1 accurate near \e x = 0.
272  *
273  * @tparam T the type of the argument and the returned value.
274  * @param[in] x
275  * @return exp(\e x) &minus; 1.
276  **********************************************************************/
277  template<typename T> static inline T expm1(T x) {
278 #if GEOGRAPHICLIB_CXX11_MATH
279  using std::expm1; return expm1(x);
280 #else
281  using std::exp; using std::abs; using std::log;
283  y = exp(x),
284  z = y - 1;
285  // The reasoning here is similar to that for log1p. The expression
286  // mathematically reduces to exp(x) - 1, and the factor z/log(y) = (y -
287  // 1)/log(y) is a slowly varying quantity near y = 1 and is accurately
288  // computed.
289  return abs(x) > 1 ? z : (z == 0 ? x : x * z / log(y));
290 #endif
291  }
292 
293  /**
294  * log(1 + \e x) accurate near \e x = 0.
295  *
296  * @tparam T the type of the argument and the returned value.
297  * @param[in] x
298  * @return log(1 + \e x).
299  **********************************************************************/
300  template<typename T> static inline T log1p(T x) {
301 #if GEOGRAPHICLIB_CXX11_MATH
302  using std::log1p; return log1p(x);
303 #else
304  using std::log;
306  y = 1 + x,
307  z = y - 1;
308  // Here's the explanation for this magic: y = 1 + z, exactly, and z
309  // approx x, thus log(y)/z (which is nearly constant near z = 0) returns
310  // a good approximation to the true log(1 + x)/x. The multiplication x *
311  // (log(y)/z) introduces little additional error.
312  return z == 0 ? x : x * log(y) / z;
313 #endif
314  }
315 
316  /**
317  * The inverse hyperbolic sine function.
318  *
319  * @tparam T the type of the argument and the returned value.
320  * @param[in] x
321  * @return asinh(\e x).
322  **********************************************************************/
323  template<typename T> static inline T asinh(T x) {
324 #if GEOGRAPHICLIB_CXX11_MATH
325  using std::asinh; return asinh(x);
326 #else
327  using std::abs; T y = abs(x); // Enforce odd parity
328  y = log1p(y * (1 + y/(hypot(T(1), y) + 1)));
329  return x < 0 ? -y : y;
330 #endif
331  }
332 
333  /**
334  * The inverse hyperbolic tangent function.
335  *
336  * @tparam T the type of the argument and the returned value.
337  * @param[in] x
338  * @return atanh(\e x).
339  **********************************************************************/
340  template<typename T> static inline T atanh(T x) {
341 #if GEOGRAPHICLIB_CXX11_MATH
342  using std::atanh; return atanh(x);
343 #else
344  using std::abs; T y = abs(x); // Enforce odd parity
345  y = log1p(2 * y/(1 - y))/2;
346  return x < 0 ? -y : y;
347 #endif
348  }
349 
350  /**
351  * The cube root function.
352  *
353  * @tparam T the type of the argument and the returned value.
354  * @param[in] x
355  * @return the real cube root of \e x.
356  **********************************************************************/
357  template<typename T> static inline T cbrt(T x) {
358 #if GEOGRAPHICLIB_CXX11_MATH
359  using std::cbrt; return cbrt(x);
360 #else
361  using std::abs; using std::pow;
362  T y = pow(abs(x), 1/T(3)); // Return the real cube root
363  return x < 0 ? -y : y;
364 #endif
365  }
366 
367  /**
368  * The error-free sum of two numbers.
369  *
370  * @tparam T the type of the argument and the returned value.
371  * @param[in] u
372  * @param[in] v
373  * @param[out] t the exact error given by (\e u + \e v) - \e s.
374  * @return \e s = round(\e u + \e v).
375  *
376  * See D. E. Knuth, TAOCP, Vol 2, 4.2.2, Theorem B. (Note that \e t can be
377  * the same as one of the first two arguments.)
378  **********************************************************************/
379  template<typename T> static inline T sum(T u, T v, T& t) {
380  GEOGRAPHICLIB_VOLATILE T s = u + v;
381  GEOGRAPHICLIB_VOLATILE T up = s - v;
382  GEOGRAPHICLIB_VOLATILE T vpp = s - up;
383  up -= u;
384  vpp -= v;
385  t = -(up + vpp);
386  // u + v = s + t
387  // = round(u + v) + t
388  return s;
389  }
390 
391  /**
392  * Normalize an angle (restricted input range).
393  *
394  * @tparam T the type of the argument and returned value.
395  * @param[in] x the angle in degrees.
396  * @return the angle reduced to the range [&minus;180&deg;, 180&deg;).
397  *
398  * \e x must lie in [&minus;540&deg;, 540&deg;).
399  **********************************************************************/
400  template<typename T> static inline T AngNormalize(T x)
401  { return x >= 180 ? x - 360 : (x < -180 ? x + 360 : x); }
402 
403  /**
404  * Normalize an arbitrary angle.
405  *
406  * @tparam T the type of the argument and returned value.
407  * @param[in] x the angle in degrees.
408  * @return the angle reduced to the range [&minus;180&deg;, 180&deg;).
409  *
410  * The range of \e x is unrestricted.
411  **********************************************************************/
412  template<typename T> static inline T AngNormalize2(T x)
413  { using std::fmod; return AngNormalize<T>(fmod(x, T(360))); }
414 
415  /**
416  * Difference of two angles reduced to [&minus;180&deg;, 180&deg;]
417  *
418  * @tparam T the type of the arguments and returned value.
419  * @param[in] x the first angle in degrees.
420  * @param[in] y the second angle in degrees.
421  * @return \e y &minus; \e x, reduced to the range [&minus;180&deg;,
422  * 180&deg;].
423  *
424  * \e x and \e y must both lie in [&minus;180&deg;, 180&deg;]. The result
425  * is equivalent to computing the difference exactly, reducing it to
426  * (&minus;180&deg;, 180&deg;] and rounding the result. Note that this
427  * prescription allows &minus;180&deg; to be returned (e.g., if \e x is
428  * tiny and negative and \e y = 180&deg;).
429  **********************************************************************/
430  template<typename T> static inline T AngDiff(T x, T y) {
431  T t, d = sum(-x, y, t);
432  if ((d - T(180)) + t > T(0)) // y - x > 180
433  d -= T(360); // exact
434  else if ((d + T(180)) + t <= T(0)) // y - x <= -180
435  d += T(360); // exact
436  return d + t;
437  }
438 
439  /**
440  * Test for finiteness.
441  *
442  * @tparam T the type of the argument.
443  * @param[in] x
444  * @return true if number is finite, false if NaN or infinite.
445  **********************************************************************/
446  template<typename T> static inline bool isfinite(T x) {
447 #if GEOGRAPHICLIB_CXX11_MATH
448  using std::isfinite; return isfinite(x);
449 #else
450  using std::abs;
451  return abs(x) <= (std::numeric_limits<T>::max)();
452 #endif
453  }
454 
455  /**
456  * The NaN (not a number)
457  *
458  * @tparam T the type of the returned value.
459  * @return NaN if available, otherwise return the max real of type T.
460  **********************************************************************/
461  template<typename T> static inline T NaN() {
462  return std::numeric_limits<T>::has_quiet_NaN ?
463  std::numeric_limits<T>::quiet_NaN() :
464  (std::numeric_limits<T>::max)();
465  }
466  /**
467  * A synonym for NaN<real>().
468  **********************************************************************/
469  static inline real NaN() { return NaN<real>(); }
470 
471  /**
472  * Test for NaN.
473  *
474  * @tparam T the type of the argument.
475  * @param[in] x
476  * @return true if argument is a NaN.
477  **********************************************************************/
478  template<typename T> static inline bool isnan(T x) {
479 #if GEOGRAPHICLIB_CXX11_MATH
480  using std::isnan; return isnan(x);
481 #else
482  return x != x;
483 #endif
484  }
485 
486  /**
487  * Infinity
488  *
489  * @tparam T the type of the returned value.
490  * @return infinity if available, otherwise return the max real.
491  **********************************************************************/
492  template<typename T> static inline T infinity() {
493  return std::numeric_limits<T>::has_infinity ?
494  std::numeric_limits<T>::infinity() :
495  (std::numeric_limits<T>::max)();
496  }
497  /**
498  * A synonym for infinity<real>().
499  **********************************************************************/
500  static inline real infinity() { return infinity<real>(); }
501 
502  /**
503  * Swap the bytes of a quantity
504  *
505  * @tparam T the type of the argument and the returned value.
506  * @param[in] x
507  * @return x with its bytes swapped.
508  **********************************************************************/
509  template<typename T> static inline T swab(T x) {
510  union {
511  T r;
512  unsigned char c[sizeof(T)];
513  } b;
514  b.r = x;
515  for (int i = sizeof(T)/2; i--; )
516  std::swap(b.c[i], b.c[sizeof(T) - 1 - i]);
517  return b.r;
518  }
519 
520 #if GEOGRAPHICLIB_PRECISION == 4
521  typedef boost::math::policies::policy
522  < boost::math::policies::domain_error
523  <boost::math::policies::errno_on_error>,
524  boost::math::policies::pole_error
525  <boost::math::policies::errno_on_error>,
526  boost::math::policies::overflow_error
527  <boost::math::policies::errno_on_error>,
528  boost::math::policies::evaluation_error
529  <boost::math::policies::errno_on_error> >
530  boost_special_functions_policy;
531 
532  static inline real hypot(real x, real y)
533  { return boost::math::hypot(x, y, boost_special_functions_policy()); }
534 
535  static inline real expm1(real x)
536  { return boost::math::expm1(x, boost_special_functions_policy()); }
537 
538  static inline real log1p(real x)
539  { return boost::math::log1p(x, boost_special_functions_policy()); }
540 
541  static inline real asinh(real x)
542  { return boost::math::asinh(x, boost_special_functions_policy()); }
543 
544  static inline real atanh(real x)
545  { return boost::math::atanh(x, boost_special_functions_policy()); }
546 
547  static inline real cbrt(real x)
548  { return boost::math::cbrt(x, boost_special_functions_policy()); }
549 
550  static inline bool isnan(real x) { return boost::math::isnan(x); }
551 
552  static inline bool isfinite(real x) { return boost::math::isfinite(x); }
553 #endif
554  };
555 
556 } // namespace GeographicLib
557 
558 #endif // GEOGRAPHICLIB_MATH_HPP
static T AngNormalize(T x)
Definition: Math.hpp:400
static T NaN()
Definition: Math.hpp:461
static T sum(T u, T v, T &t)
Definition: Math.hpp:379
static int digits10()
Definition: Math.hpp:173
static int set_digits(int ndigits)
Definition: Math.hpp:161
static T pi()
Definition: Math.hpp:214
#define GEOGRAPHICLIB_EXPORT
Definition: Constants.hpp:69
static T infinity()
Definition: Math.hpp:492
#define GEOGRAPHICLIB_WORDS_BIGENDIAN
Definition: Math.hpp:40
static real degree()
Definition: Math.hpp:235
GeographicLib::Math::real real
Definition: GeodSolve.cpp:32
static T cbrt(T x)
Definition: Math.hpp:357
static bool isfinite(T x)
Definition: Math.hpp:446
static bool isnan(T x)
Definition: Math.hpp:478
Mathematical functions needed by GeographicLib.
Definition: Math.hpp:102
static T atanh(T x)
Definition: Math.hpp:340
static T expm1(T x)
Definition: Math.hpp:277
#define GEOGRAPHICLIB_PRECISION
Definition: Math.hpp:57
#define GEOGRAPHICLIB_VOLATILE
Definition: Math.hpp:84
static T asinh(T x)
Definition: Math.hpp:323
static int extra_digits()
Definition: Math.hpp:185
static T hypot(T x, T y)
Definition: Math.hpp:255
static T sq(T x)
Definition: Math.hpp:244
static real pi()
Definition: Math.hpp:222
Namespace for GeographicLib.
Definition: Accumulator.cpp:12
static T degree()
Definition: Math.hpp:228
static T AngDiff(T x, T y)
Definition: Math.hpp:430
static real NaN()
Definition: Math.hpp:469
static T log1p(T x)
Definition: Math.hpp:300
static T swab(T x)
Definition: Math.hpp:509
static real infinity()
Definition: Math.hpp:500
Header for GeographicLib::Constants class.
static int digits()
Definition: Math.hpp:145
static T AngNormalize2(T x)
Definition: Math.hpp:412