Browse Source

core: fix an accuracy error in real::re() and real::sqrt() introduced in

the 16-to-32-bit refactoring.
legacy
Sam Hocevar sam 13 years ago
parent
commit
5d9167bda0
3 changed files with 25 additions and 19 deletions
  1. +7
    -9
      src/real.cpp
  2. +2
    -1
      src/real.h
  3. +16
    -9
      test/unit/real.cpp

+ 7
- 9
src/real.cpp View File

@@ -22,8 +22,6 @@ using namespace std;
namespace lol
{

static int const BIGIT_BITS = 32;

real::real(float f) { *this = (double)f; }
real::real(int i) { *this = (double)i; }
real::real(unsigned int i) { *this = (double)i; }
@@ -500,9 +498,9 @@ real re(real const &x)
exponent = -exponent + (v.x >> 23) - (u.x >> 23);
ret.m_signexp |= (exponent - 1) & 0x7fffffffu;

/* FIXME: log2(BIGITS) steps of Newton-Raphson seems to be enough for
/* FIXME: 1+log2(BIGITS) steps of Newton-Raphson seems to be enough for
* convergence, but this hasn't been checked seriously. */
for (int i = 2; i < real::BIGITS; i *= 2)
for (int i = 1; i <= real::BIGITS; i *= 2)
ret = ret * (real::R_2 - ret * x);

return ret;
@@ -544,9 +542,9 @@ real sqrt(real const &x)
exponent = exponent + (v.x >> 23) - (u.x >> 23);
ret.m_signexp |= exponent & 0x7fffffffu;

/* FIXME: log2(BIGITS) steps of Newton-Raphson seems to be enough for
/* FIXME: 1+log2(BIGITS) steps of Newton-Raphson seems to be enough for
* convergence, but this hasn't been checked seriously. */
for (int i = 2; i < real::BIGITS; i *= 2)
for (int i = 1; i <= real::BIGITS; i *= 2)
{
ret = ret * (real::R_3 - ret * ret * x);
ret.m_signexp--;
@@ -668,10 +666,10 @@ real floor(real const &x)
{
if (exponent <= 0)
ret.m_mantissa[i] = 0;
else if (exponent < BIGIT_BITS)
ret.m_mantissa[i] &= ~((1 << (BIGIT_BITS - exponent)) - 1);
else if (exponent < real::BIGIT_BITS)
ret.m_mantissa[i] &= ~((1 << (real::BIGIT_BITS - exponent)) - 1);

exponent -= BIGIT_BITS;
exponent -= real::BIGIT_BITS;
}

return ret;


+ 2
- 1
src/real.h View File

@@ -104,12 +104,13 @@ public:
static real const R_SQRT3;
static real const R_SQRT1_2;

private:
/* XXX: changing this requires tuning real::fres (the number of
* Newton-Raphson iterations) and real::print (the number of printed
* digits) */
static int const BIGITS = 16;
static int const BIGIT_BITS = 32;

private:
uint32_t m_size;
uint32_t m_signexp;
uint32_t m_mantissa[BIGITS];


+ 16
- 9
test/unit/real.cpp View File

@@ -180,16 +180,13 @@ LOLUNIT_FIXTURE(RealTest)
LOLUNIT_ASSERT_EQUAL(m4, -1.5f * -1.5f);
}

LOLUNIT_TEST(Division)
LOLUNIT_TEST(ExactDivision)
{
real a1(1.0f);
real a2(2.0f);

float m1 = a1 / a1;
float m2 = a2 / a1;
float m3 = a1 / a2;
float m4 = a2 / a2;
float m5 = a1 / -a2;
float m1 = real::R_1 / real::R_1;
float m2 = real::R_2 / real::R_1;
float m3 = real::R_1 / real::R_2;
float m4 = real::R_2 / real::R_2;
float m5 = real::R_1 / -real::R_2;

LOLUNIT_ASSERT_EQUAL(m1, 1.0f);
LOLUNIT_ASSERT_EQUAL(m2, 2.0f);
@@ -198,6 +195,16 @@ LOLUNIT_FIXTURE(RealTest)
LOLUNIT_ASSERT_EQUAL(m5, -0.5f);
}

LOLUNIT_TEST(InexactDivision)
{
/* 1 / 3 * 3 should be close to 1... check that it does not differ
* by more than 2^-k where k is the number of bits in the mantissa. */
real a = real::R_1 / real::R_3 * real::R_3;
real b = (real::R_1 - a) << (real::BIGITS * real::BIGIT_BITS);

LOLUNIT_ASSERT_LEQUAL((double)fabs(b), 1.0);
}

LOLUNIT_TEST(Shift)
{
real a1(1.5);


Loading…
Cancel
Save