#include <GeographicLib/Math.hpp>
namespace GeographicLib {
using namespace std;
void Math::dummy() {
static_assert(GEOGRAPHICLIB_PRECISION >= 1, "Bad value of precision");
}
int Math::digits() {
#if GEOGRAPHICLIB_PRECISION == 5
return numeric_limits<real>::digits();
#else
return numeric_limits<real>::digits;
#endif
}
int Math::set_digits(int ndigits) {
#if GEOGRAPHICLIB_PRECISION >= 5
# if GEOGRAPHICLIB_PRECISION > 5
ndigits = numeric_limits<real>::digits;
# endif
mpfr::mpreal::set_default_prec(ndigits >= 2 ? ndigits : 2);
#else
(void) ndigits;
#endif
return digits();
}
int Math::digits10() {
#if GEOGRAPHICLIB_PRECISION == 5
return numeric_limits<real>::digits10();
#else
return numeric_limits<real>::digits10;
#endif
}
int Math::extra_digits() {
return
digits10() > numeric_limits<double>::digits10 ?
digits10() - numeric_limits<double>::digits10 : 0;
}
template<typename T> T Math::sum(T u, T v, T& t) {
GEOGRAPHICLIB_VOLATILE T s = u + v;
GEOGRAPHICLIB_VOLATILE T up = s - v;
GEOGRAPHICLIB_VOLATILE T vpp = s - up;
up -= u;
vpp -= v;
t = s != 0 ? T(0) - (up + vpp) : s;
return s;
}
template<typename T> T Math::AngNormalize(T x) {
T y = remainder(x, T(td));
#if GEOGRAPHICLIB_PRECISION == 4
if (y == 0) y = copysign(y, x);
#endif
return fabs(y) == T(hd) ? copysign(T(hd), x) : y;
}
template<typename T> T Math::AngDiff(T x, T y, T& e) {
T d = sum(remainder(-x, T(td)), remainder( y, T(td)), e);
d = sum(remainder(d, T(td)), e, e);
if (d == 0 || fabs(d) == hd)
d = copysign(d, e == 0 ? y - x : -e);
return d;
}
template<typename T> T Math::AngRound(T x) {
static const T z = T(1)/T(16);
GEOGRAPHICLIB_VOLATILE T y = fabs(x);
GEOGRAPHICLIB_VOLATILE T w = z - y;
y = w > 0 ? z - w : y;
return copysign(y, x);
}
template<typename T> void Math::sincosd(T x, T& sinx, T& cosx) {
T d, r; int q = 0;
d = remquo(x, T(qd), &q); r = d * degree<T>();
T s = sin(r), c = cos(r);
if (2 * fabs(d) == qd) {
c = sqrt(1/T(2));
s = copysign(c, r);
} else if (3 * fabs(d) == qd) {
c = sqrt(T(3))/2;
s = copysign(1/T(2), r);
}
switch (unsigned(q) & 3U) {
case 0U: sinx = s; cosx = c; break;
case 1U: sinx = c; cosx = -s; break;
case 2U: sinx = -s; cosx = -c; break;
default: sinx = -c; cosx = s; break; }
cosx += T(0); if (sinx == 0) sinx = copysign(sinx, x); }
template<typename T> void Math::sincosde(T x, T t, T& sinx, T& cosx) {
int q = 0;
T d = AngRound(remquo(x, T(qd), &q) + t), r = d * degree<T>();
T s = sin(r), c = cos(r);
if (2 * fabs(d) == qd) {
c = sqrt(1/T(2));
s = copysign(c, r);
} else if (3 * fabs(d) == qd) {
c = sqrt(T(3))/2;
s = copysign(1/T(2), r);
}
switch (unsigned(q) & 3U) {
case 0U: sinx = s; cosx = c; break;
case 1U: sinx = c; cosx = -s; break;
case 2U: sinx = -s; cosx = -c; break;
default: sinx = -c; cosx = s; break; }
cosx += T(0); if (sinx == 0) sinx = copysign(sinx, x+t); }
template<typename T> T Math::sind(T x) {
int q = 0;
T d = remquo(x, T(qd), &q), r = d * degree<T>();
unsigned p = unsigned(q);
r = p & 1U ? (2 * fabs(d) == qd ? sqrt(1/T(2)) :
(3 * fabs(d) == qd ? sqrt(T(3))/2 : cos(r))) :
copysign(2 * fabs(d) == qd ? sqrt(1/T(2)) :
(3 * fabs(d) == qd ? 1/T(2) : sin(r)), r);
if (p & 2U) r = -r;
if (r == 0) r = copysign(r, x);
return r;
}
template<typename T> T Math::cosd(T x) {
int q = 0;
T d = remquo(x, T(qd), &q), r = d * degree<T>();
unsigned p = unsigned(q + 1);
r = p & 1U ? (2 * fabs(d) == qd ? sqrt(1/T(2)) :
(3 * fabs(d) == qd ? sqrt(T(3))/2 : cos(r))) :
copysign(2 * fabs(d) == qd ? sqrt(1/T(2)) :
(3 * fabs(d) == qd ? 1/T(2) : sin(r)), r);
if (p & 2U) r = -r;
return T(0) + r;
}
template<typename T> T Math::tand(T x) {
static const T overflow = 1 / sq(numeric_limits<T>::epsilon());
T s, c;
sincosd(x, s, c);
T r = s / c; return min(max(r, -overflow), overflow);
}
template<typename T> T Math::atan2d(T y, T x) {
int q = 0;
if (fabs(y) > fabs(x)) { swap(x, y); q = 2; }
if (signbit(x)) { x = -x; ++q; }
T ang = (atan2(y, x) / pi<T>()) * T(hd);
switch (q) {
case 1: ang = copysign(T(hd), y) - ang; break;
case 2: ang = qd - ang; break;
case 3: ang = -qd + ang; break;
default: break;
}
return ang;
}
template<typename T> T Math::atand(T x)
{ return atan2d(x, T(1)); }
template<typename T> T Math::eatanhe(T x, T es) {
return es > 0 ? es * atanh(es * x) : -es * atan(es * x);
}
template<typename T> T Math::taupf(T tau, T es) {
if (isfinite(tau)) {
T tau1 = hypot(T(1), tau),
sig = sinh( eatanhe(tau / tau1, es ) );
return hypot(T(1), sig) * tau - sig * tau1;
} else
return tau;
}
template<typename T> T Math::tauf(T taup, T es) {
static const int numit = 5;
static const T tol = sqrt(numeric_limits<T>::epsilon()) / 10;
static const T taumax = 2 / sqrt(numeric_limits<T>::epsilon());
T e2m = 1 - sq(es),
tau = fabs(taup) > 70 ? taup * exp(eatanhe(T(1), es)) : taup/e2m,
stol = tol * fmax(T(1), fabs(taup));
if (!(fabs(tau) < taumax)) return tau; for (int i = 0;
i < numit ||
GEOGRAPHICLIB_PANIC("Convergence failure in Math::tauf");
++i) {
T taupa = taupf(tau, es),
dtau = (taup - taupa) * (1 + e2m * sq(tau)) /
( e2m * hypot(T(1), tau) * hypot(T(1), taupa) );
tau += dtau;
if (!(fabs(dtau) >= stol))
break;
}
return tau;
}
template<typename T> T Math::hypot3(T x, T y, T z) {
#if __cplusplus < 201703L || GEOGRAPHICLIB_PRECISION == 4
return sqrt(x*x + y*y + z*z);
#else
return hypot(x, y, z);
#endif
}
template<typename T> T Math::NaN() {
#if defined(_MSC_VER)
return numeric_limits<T>::has_quiet_NaN ?
numeric_limits<T>::quiet_NaN() :
(numeric_limits<T>::max)();
#else
return numeric_limits<T>::has_quiet_NaN ?
numeric_limits<T>::quiet_NaN() :
numeric_limits<T>::max();
#endif
}
template<typename T> T Math::infinity() {
#if defined(_MSC_VER)
return numeric_limits<T>::has_infinity ?
numeric_limits<T>::infinity() :
(numeric_limits<T>::max)();
#else
return numeric_limits<T>::has_infinity ?
numeric_limits<T>::infinity() :
numeric_limits<T>::max();
#endif
}
#define GEOGRAPHICLIB_MATH_INSTANTIATE(T) \
template T GEOGRAPHICLIB_EXPORT Math::sum <T>(T, T, T&); \
template T GEOGRAPHICLIB_EXPORT Math::AngNormalize <T>(T); \
template T GEOGRAPHICLIB_EXPORT Math::AngDiff <T>(T, T, T&); \
template T GEOGRAPHICLIB_EXPORT Math::AngRound <T>(T); \
template void GEOGRAPHICLIB_EXPORT Math::sincosd <T>(T, T&, T&); \
template void GEOGRAPHICLIB_EXPORT Math::sincosde <T>(T, T, T&, T&); \
template T GEOGRAPHICLIB_EXPORT Math::sind <T>(T); \
template T GEOGRAPHICLIB_EXPORT Math::cosd <T>(T); \
template T GEOGRAPHICLIB_EXPORT Math::tand <T>(T); \
template T GEOGRAPHICLIB_EXPORT Math::atan2d <T>(T, T); \
template T GEOGRAPHICLIB_EXPORT Math::atand <T>(T); \
template T GEOGRAPHICLIB_EXPORT Math::eatanhe <T>(T, T); \
template T GEOGRAPHICLIB_EXPORT Math::taupf <T>(T, T); \
template T GEOGRAPHICLIB_EXPORT Math::tauf <T>(T, T); \
template T GEOGRAPHICLIB_EXPORT Math::hypot3 <T>(T, T, T); \
template T GEOGRAPHICLIB_EXPORT Math::NaN <T>(); \
template T GEOGRAPHICLIB_EXPORT Math::infinity <T>();
GEOGRAPHICLIB_MATH_INSTANTIATE(float)
GEOGRAPHICLIB_MATH_INSTANTIATE(double)
#if GEOGRAPHICLIB_HAVE_LONG_DOUBLE
GEOGRAPHICLIB_MATH_INSTANTIATE(long double)
#endif
#if GEOGRAPHICLIB_PRECISION > 3
GEOGRAPHICLIB_MATH_INSTANTIATE(Math::real)
#endif
#undef GEOGRAPHICLIB_MATH_INSTANTIATE
template int GEOGRAPHICLIB_EXPORT Math::NaN <int>();
template int GEOGRAPHICLIB_EXPORT Math::infinity<int>();
}