Browse Source

core: allow to cast reals to doubles in addition to floats.

legacy
Sam Hocevar sam 13 years ago
parent
commit
cdc155c42b
3 changed files with 71 additions and 19 deletions
  1. +50
    -19
      src/real.cpp
  2. +2
    -0
      src/real.h
  3. +19
    -0
      test/unit/real.cpp

+ 50
- 19
src/real.cpp View File

@@ -24,45 +24,76 @@ namespace lol


real::real(float f) 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) switch (exponent)
{ {
case 0x00: case 0x00:
case 0xff:
m_signexp = sign | exponent;
m_signexp = sign;
break;
case 0x7ff:
m_signexp = sign | 0x7fffffffu;
break; break;
default: default:
m_signexp = sign | (exponent + (1 << 30) - (1 << 7));
m_signexp = sign | (exponent + (1 << 30) - (1 << 10));
break; 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 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) 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 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 real real::operator -() const


+ 2
- 0
src/real.h View File

@@ -28,8 +28,10 @@ class real
public: public:
inline real() { } inline real() { }
real(float f); real(float f);
real(double f);


operator float() const; operator float() const;
operator double() const;


real operator -() const; real operator -() const;
real operator +(real const &x) const; real operator +(real const &x) const;


+ 19
- 0
test/unit/real.cpp View File

@@ -29,12 +29,31 @@ LOLUNIT_FIXTURE(RealTest)
float a3 = real(1.0f); float a3 = real(1.0f);
float a4 = real(-1.0f); float a4 = real(-1.0f);
float a5 = real(1.5f); float a5 = real(1.5f);
float a6 = real(12345678.0f);


LOLUNIT_ASSERT_EQUAL(a1, 0.0f); LOLUNIT_ASSERT_EQUAL(a1, 0.0f);
LOLUNIT_ASSERT_EQUAL(a2, -0.0f); LOLUNIT_ASSERT_EQUAL(a2, -0.0f);
LOLUNIT_ASSERT_EQUAL(a3, 1.0f); LOLUNIT_ASSERT_EQUAL(a3, 1.0f);
LOLUNIT_ASSERT_EQUAL(a4, -1.0f); LOLUNIT_ASSERT_EQUAL(a4, -1.0f);
LOLUNIT_ASSERT_EQUAL(a5, 1.5f); 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) LOLUNIT_TEST(test_real_neg)


Loading…
Cancel
Save