From cdc155c42b702a45044b2fd6245f650f0170bb47 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Thu, 22 Sep 2011 16:16:51 +0000 Subject: [PATCH] core: allow to cast reals to doubles in addition to floats. --- src/real.cpp | 69 +++++++++++++++++++++++++++++++++------------- src/real.h | 2 ++ test/unit/real.cpp | 19 +++++++++++++ 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/src/real.cpp b/src/real.cpp index 51c1fde7..d012ea55 100644 --- a/src/real.cpp +++ b/src/real.cpp @@ -24,45 +24,76 @@ namespace lol real::real(float f) { - union { float f; uint32_t x; } u = { f }; + new(this) real((double)f); +} + +real::real(double d) +{ + union { double d; uint64_t x; } u = { d }; - uint32_t sign = u.x & 0x80000000u; - uint32_t exponent = (u.x >> 23) & 0xff; + uint32_t sign = (u.x >> 63) << 31; + uint32_t exponent = (u.x << 1) >> 53; switch (exponent) { case 0x00: - case 0xff: - m_signexp = sign | exponent; + m_signexp = sign; + break; + case 0x7ff: + m_signexp = sign | 0x7fffffffu; break; default: - m_signexp = sign | (exponent + (1 << 30) - (1 << 7)); + m_signexp = sign | (exponent + (1 << 30) - (1 << 10)); break; } - m_mantissa[0] = u.x >> 7; - m_mantissa[1] = u.x << 9; - memset(m_mantissa + 2, 0, sizeof(m_mantissa) - sizeof(m_mantissa[0])); + m_mantissa[0] = u.x >> 36; + m_mantissa[1] = u.x >> 20; + m_mantissa[2] = u.x >> 4; + m_mantissa[3] = u.x << 12; + memset(m_mantissa + 4, 0, sizeof(m_mantissa) - 4 * sizeof(m_mantissa[0])); } real::operator float() const { - union { float f; uint32_t x; } u; + return (float)(double)(*this); +} - uint32_t sign = m_signexp & 0x80000000u; - uint32_t exponent = m_signexp & 0x7fffffffu; - uint32_t mantissa = (m_mantissa[0] << 7) | (m_mantissa[1] >> 9); +real::operator double() const +{ + union { double d; uint64_t x; } u; - int e = (int)exponent - (1 << 30) + (1 << 7); + /* Get sign */ + u.x = m_signexp >> 31; + u.x <<= 11; + + /* Compute new exponent */ + uint32_t exponent = (m_signexp << 1) >> 1; + int e = (int)exponent - (1 << 30) + (1 << 10); if (e < 0) - u.x = sign; - else if (e >= 0xff) - u.x = sign | (0xff << 23); + u.x <<= 52; + else if (e >= 0x7ff) + { + u.x |= 0x7ff; + u.x <<= 52; + } else - u.x = sign | (e << 23) | mantissa; + { + u.x |= e; + + /* Store mantissa if necessary */ + u.x <<= 16; + u.x |= m_mantissa[0]; + u.x <<= 16; + u.x |= m_mantissa[1]; + u.x <<= 16; + u.x |= m_mantissa[2]; + u.x <<= 4; + u.x |= m_mantissa[3] >> 12; + } - return u.f; + return u.d; } real real::operator -() const diff --git a/src/real.h b/src/real.h index dd781005..8e029c78 100644 --- a/src/real.h +++ b/src/real.h @@ -28,8 +28,10 @@ class real public: inline real() { } real(float f); + real(double f); operator float() const; + operator double() const; real operator -() const; real operator +(real const &x) const; diff --git a/test/unit/real.cpp b/test/unit/real.cpp index a7141132..b70f6935 100644 --- a/test/unit/real.cpp +++ b/test/unit/real.cpp @@ -29,12 +29,31 @@ LOLUNIT_FIXTURE(RealTest) float a3 = real(1.0f); float a4 = real(-1.0f); float a5 = real(1.5f); + float a6 = real(12345678.0f); LOLUNIT_ASSERT_EQUAL(a1, 0.0f); LOLUNIT_ASSERT_EQUAL(a2, -0.0f); LOLUNIT_ASSERT_EQUAL(a3, 1.0f); LOLUNIT_ASSERT_EQUAL(a4, -1.0f); LOLUNIT_ASSERT_EQUAL(a5, 1.5f); + LOLUNIT_ASSERT_EQUAL(a6, 12345678.0f); + } + + LOLUNIT_TEST(test_real_from_double) + { + double a1 = real(0.0); + double a2 = real(-0.0); + double a3 = real(1.0); + double a4 = real(-1.0); + double a5 = real(1.5); + double a6 = real(1234567876543210.0); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(a1, 0.0, 0.0); + LOLUNIT_ASSERT_DOUBLES_EQUAL(a2, -0.0, 0.0); + LOLUNIT_ASSERT_DOUBLES_EQUAL(a3, 1.0, 0.0); + LOLUNIT_ASSERT_DOUBLES_EQUAL(a4, -1.0, 0.0); + LOLUNIT_ASSERT_DOUBLES_EQUAL(a5, 1.5, 0.0); + LOLUNIT_ASSERT_DOUBLES_EQUAL(a6, 1234567876543210.0, 0.0); } LOLUNIT_TEST(test_real_neg)