diff --git a/src/lol/math/real.h b/src/lol/math/real.h index 83ae0676..bf9f655b 100644 --- a/src/lol/math/real.h +++ b/src/lol/math/real.h @@ -45,6 +45,7 @@ public: Real(float f); Real(double f); + Real(long double f); Real(int32_t i); Real(uint32_t i); Real(int64_t i); @@ -54,6 +55,7 @@ public: operator float() const; operator double() const; + operator long double() const; operator int() const; operator unsigned int() const; @@ -171,6 +173,7 @@ public: __LOL_REAL_OP_HELPER_INT(unsigned int) __LOL_REAL_OP_HELPER_FLOAT(float) __LOL_REAL_OP_HELPER_FLOAT(double) + __LOL_REAL_OP_HELPER_FLOAT(long double) /* Constants */ static Real const& R_0(); @@ -217,6 +220,7 @@ template<> real const &real::operator =(real const &x); template<> real::~Real(); template<> real::Real(float f); template<> real::Real(double f); +template<> real::Real(long double f); template<> real::Real(int32_t i); template<> real::Real(uint32_t i); template<> real::Real(int64_t i); @@ -225,6 +229,7 @@ template<> real::Real(char const *str); template<> real::operator float() const; template<> real::operator double() const; +template<> real::operator long double() const; template<> real::operator int() const; template<> real::operator unsigned int() const; template<> real real::operator +() const; diff --git a/src/math/real.cpp b/src/math/real.cpp index a4b2fe77..b499ac96 100644 --- a/src/math/real.cpp +++ b/src/math/real.cpp @@ -136,6 +136,16 @@ template<> real::Real(double d) memset(m_mantissa + 2, 0, (BIGITS - 2) * sizeof(m_mantissa[0])); } +template<> real::Real(long double f) +{ + /* We don’t know the long double layout, so we split it into + * two doubles instead. */ + double hi = double(f); + double lo = double(f - (long double)hi);; + new(this) real(hi); + *this += lo; +} + template<> real::operator float() const { return (float)(double)(*this); } template<> real::operator int() const { return (int)(double)(*this); } template<> real::operator unsigned() const { return (unsigned)(double)(*this); } @@ -175,6 +185,13 @@ template<> real::operator double() const return u.d; } +template<> real::operator long double() const +{ + double hi = double(*this); + double lo = double(*this - hi); + return (long double)(hi) + (long double)(lo); +} + /* * Create a real number from an ASCII representation */ diff --git a/src/t/math/real.cpp b/src/t/math/real.cpp index 404f613e..0ad9ddaa 100644 --- a/src/t/math/real.cpp +++ b/src/t/math/real.cpp @@ -102,6 +102,22 @@ lolunit_declare_fixture(real_test) lolunit_assert_doubles_equal(a6, 1234567876543210.0, 0.0); } + lolunit_declare_test(long_double_to_real) + { + real r((long double)1 / 3); + + // Count how many bits are correct + int ok_bits = 0; + while (int(r) == 0) + { + r = (r * 4) - 1; + ok_bits += 2; + } + + // 64 bits means our precision is better than double + lolunit_assert_greater(ok_bits, 64); + } + lolunit_declare_test(init) { real r;