From 3025ea2207008a8a117f11d2b50a3c2c41901e34 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Sat, 26 Aug 2017 22:04:45 +0200 Subject: [PATCH] Implement real::R_INF and real::R_NAN. --- src/lol/math/real.h | 5 +++- src/math/real.cpp | 64 +++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/src/lol/math/real.h b/src/lol/math/real.h index e2190c03..92184a92 100644 --- a/src/lol/math/real.h +++ b/src/lol/math/real.h @@ -185,7 +185,7 @@ public: __LOL_REAL_OP_HELPER_FLOAT(long double) /* Constants */ - static Real const& R_0(); + static Real const R_0(); static Real const& R_1(); static Real const& R_2(); static Real const& R_3(); @@ -209,6 +209,9 @@ public: static Real const& R_SQRT3(); static Real const& R_SQRT1_2(); + static Real const R_INF(); + static Real const R_NAN(); + static Real const& R_MIN(); static Real const& R_MAX(); diff --git a/src/math/real.cpp b/src/math/real.cpp index f2fdda5d..f04a8164 100644 --- a/src/math/real.cpp +++ b/src/math/real.cpp @@ -38,6 +38,11 @@ static real load_min(); static real load_max(); static real load_pi(); +/* These getters do not need caching, their return values are small */ +template<> real const real::R_0() { return real(); } +template<> real const real::R_INF() { real ret; ret.m_inf = true; return ret; } +template<> real const real::R_NAN() { real ret; ret.m_nan = true; return ret; } + #define LOL_CONSTANT_GETTER(name, value) \ template<> real const& real::name() \ { \ @@ -47,17 +52,16 @@ static real load_pi(); * the value with the desired precision. */ \ if (prev_bigit_count != DEFAULT_BIGIT_COUNT) \ { \ - ret = value; \ + ret = (value); \ prev_bigit_count = DEFAULT_BIGIT_COUNT; \ } \ return ret; \ } -LOL_CONSTANT_GETTER(R_0, (real)0.0); -LOL_CONSTANT_GETTER(R_1, (real)1.0); -LOL_CONSTANT_GETTER(R_2, (real)2.0); -LOL_CONSTANT_GETTER(R_3, (real)3.0); -LOL_CONSTANT_GETTER(R_10, (real)10.0); +LOL_CONSTANT_GETTER(R_1, real(1.0)); +LOL_CONSTANT_GETTER(R_2, real(2.0)); +LOL_CONSTANT_GETTER(R_3, real(3.0)); +LOL_CONSTANT_GETTER(R_10, real(10.0)); LOL_CONSTANT_GETTER(R_MIN, load_min()); LOL_CONSTANT_GETTER(R_MAX, load_max()); @@ -573,6 +577,10 @@ template<> real const &real::operator /=(real const &x) template<> bool real::operator ==(real const &x) const { + /* If NaN is involved, return false */ + if (is_nan() || x.is_nan()) + return false; + /* If both zero, they are equal; if either is zero, they are different */ if (is_zero() || x.is_zero()) return is_zero() && x.is_zero(); @@ -583,11 +591,15 @@ template<> bool real::operator ==(real const &x) const template<> bool real::operator !=(real const &x) const { - return !(*this == x); + return !(is_nan() || x.is_nan() || *this == x); } template<> bool real::operator <(real const &x) const { + /* If NaN is involved, return false */ + if (is_nan() || x.is_nan()) + return false; + /* Ensure we are positive */ if (is_negative()) return -*this > -x; @@ -614,11 +626,15 @@ template<> bool real::operator <(real const &x) const template<> bool real::operator <=(real const &x) const { - return !(*this > x); + return !(is_nan() || x.is_nan() || *this > x); } template<> bool real::operator >(real const &x) const { + /* If NaN is involved, return false */ + if (is_nan() || x.is_nan()) + return false; + /* Ensure we are positive */ if (is_negative()) return -*this < -x; @@ -649,7 +665,7 @@ template<> bool real::operator >(real const &x) const template<> bool real::operator >=(real const &x) const { - return !(*this < x); + return !(is_nan() || x.is_nan() || *this < x); } template<> bool real::operator !() const @@ -684,11 +700,7 @@ template<> real inverse(real const &x) /* If zero, return infinite */ if (x.is_zero()) - { - ret.m_sign = x.m_sign; - ret.m_inf = true; - return ret; - } + return copysign(real::R_INF(), x); /* Use the system's float inversion to approximate 1/x */ union { float f; uint32_t x; } u = { 1.0f }; @@ -716,11 +728,7 @@ template<> real sqrt(real const &x) /* if negative, return NaN */ if (x.is_negative()) - { - real ret; - ret.m_nan = true; - return ret; - } + return real::R_NAN(); int tweak = x.m_exponent & 1; @@ -950,13 +958,10 @@ template<> real log(real const &x) { /* Strategy for log(x): if x = 2^E*M then log(x) = E log(2) + log(M), * with the property that M is in [1..2[, so fast_log() applies here. */ - real tmp; if (x.is_negative() || x.is_zero()) - { - tmp.m_nan = true; - return tmp; - } - tmp = x; + return real::R_NAN(); + + real tmp(x); tmp.m_exponent = 0; return real(x.m_exponent) * real::R_LN2() + fast_log(tmp); } @@ -964,13 +969,10 @@ template<> real log(real const &x) template<> real log2(real const &x) { /* Strategy for log2(x): see log(x). */ - real tmp; if (x.is_negative() || x.is_zero()) - { - tmp.m_nan = true; - return tmp; - } - tmp = x; + return real::R_NAN(); + + real tmp(x); tmp.m_exponent = 0; return real(x.m_exponent) + fast_log(tmp) * real::R_LOG2E(); }