From 884978c71bd3e57f8296719e136c14a1b5cbe4ea Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Thu, 22 Sep 2011 07:15:56 +0000 Subject: [PATCH] core: handle zero, negative zero and infinite in the real constructor, and add a test suite check for unary minus. --- src/real.cpp | 33 +++++++++++++++++++++++++++------ test/unit/real.cpp | 29 +++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/real.cpp b/src/real.cpp index f7dfb45d..709d4082 100644 --- a/src/real.cpp +++ b/src/real.cpp @@ -27,9 +27,19 @@ real::real(float f) union { float f; uint32_t x; } u = { f }; uint32_t sign = u.x & 0x80000000u; - int e = ((u.x >> 23) & 0xff) + (1 << 30) - (1 << 7); + uint32_t exponent = (u.x >> 23) & 0xff; + + switch (exponent) + { + case 0x00: + case 0xff: + m_signexp = sign | exponent; + break; + default: + m_signexp = sign | (exponent + (1 << 30) - (1 << 7)); + break; + } - m_signexp = sign | e; m_mantissa[0] = u.x >> 7; m_mantissa[1] = u.x << 9; memset(m_mantissa + 2, 0, sizeof(m_mantissa) - sizeof(m_mantissa[0])); @@ -39,10 +49,18 @@ real::operator float() const { union { float f; uint32_t x; } u; - u.x = m_mantissa[0] << 7; - u.x |= m_mantissa[1] >> 9; - u.x |= ((m_signexp & 0x7fffffffu) - (1 << 30) + (1 << 7)) << 23; - u.x |= m_signexp & 0x80000000u; + uint32_t sign = m_signexp & 0x80000000u; + uint32_t exponent = m_signexp & 0x7fffffffu; + uint32_t mantissa = (m_mantissa[0] << 7) | (m_mantissa[1] >> 9); + + int e = (int)(m_signexp & 0x7fffffffu) - (1 << 30) + (1 << 7); + + if (e < 0) + u.x = sign; + else if (e >= 0xff) + u.x = sign | (0xff << 23); + else + u.x = sign | (e << 23) | mantissa; return u.f; } @@ -58,6 +76,9 @@ real real::operator +(real const &x) const if ((m_signexp << 1) < (x.m_signexp << 1)) return x + *this; + if (x.m_signexp << 1 == 0) + return *this; + /* For now, assume both numbers are positive. */ real ret; diff --git a/test/unit/real.cpp b/test/unit/real.cpp index d5ab66ab..f03b5f50 100644 --- a/test/unit/real.cpp +++ b/test/unit/real.cpp @@ -25,13 +25,30 @@ LOLUNIT_FIXTURE(RealTest) public: LOLUNIT_TEST(test_real_from_float) { - float x = real(0.0f); - float y = real(1.0f); - float z = real(1.5f); + float a1 = real(0.0f); + float a2 = real(-0.0f); + float a3 = real(1.0f); + float a4 = real(-1.0f); + float a5 = real(1.5f); - LOLUNIT_ASSERT_EQUAL(x, 0.0f); - LOLUNIT_ASSERT_EQUAL(y, 1.0f); - LOLUNIT_ASSERT_EQUAL(z, 1.5f); + 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_TEST(test_real_neg) + { + float a1 = - real(1.0f); + float a2 = - real(-1.0f); + float a3 = - real(0.0f); + float a4 = - real(-0.0f); + + LOLUNIT_ASSERT_EQUAL(a1, -1.0f); + LOLUNIT_ASSERT_EQUAL(a2, 1.0f); + LOLUNIT_ASSERT_EQUAL(a3, -0.0f); + LOLUNIT_ASSERT_EQUAL(a4, 0.0f); } LOLUNIT_TEST(test_real_add)