core: int64x64_t GetInt() and Round(), with test cases

Merge of !473
This commit is contained in:
Peter D. Barnes, Jr
2020-11-09 18:50:04 -08:00
committed by Tom Henderson
parent de9771c6aa
commit eb432c90a5
4 changed files with 148 additions and 0 deletions

View File

@@ -235,6 +235,37 @@ public:
return retval;
}
/**
* Truncate to an integer.
* Truncation is always toward zero,
* \return The value truncated toward zero.
*/
int64_t GetInt (void) const
{
const bool negative = _v < 0;
const uint128_t value = negative ? -_v : _v;
int64_t retval = value >> 64;
retval = negative ? - retval : retval;
return retval;
}
/**
* Round to the nearest int.
* Similar to std::round this rounds halfway cases away from zero,
* regardless of the current (floating) rounding mode.
* \return The value rounded to the nearest int.
*/
int64_t Round (void) const
{
const bool negative = _v < 0;
int64x64_t value = (negative ? -(*this) : *this);
const int64x64_t half (0, 1LL << 63);
value += half;
int64_t retval = value.GetHigh ();
retval = negative ? - retval : retval;
return retval;
}
/**
* Multiply this value by a Q0.128 value, presumably representing an inverse,
* completing a division operation.

View File

@@ -226,6 +226,37 @@ public:
return _v.lo;
}
/**
* Truncate to an integer.
* Truncation is always toward zero,
* \return The value truncated toward zero.
*/
int64_t GetInt (void) const
{
const bool negative = _cairo_int128_negative (_v);
const cairo_int128_t value = negative ? _cairo_int128_negate (_v) : _v;
int64_t retval = value.hi;
retval = negative ? - retval : retval;
return retval;
}
/**
* Round to the nearest int.
* Similar to std::round this rounds halfway cases away from zero,
* regardless of the current (floating) rounding mode.
* \return The value rounded to the nearest int.
*/
int64_t Round (void) const
{
const bool negative = _cairo_int128_negative (_v);
cairo_uint128_t value = negative ? _cairo_int128_negate (_v) : _v;
cairo_uint128_t half {1ULL << 63, 0}; // lo, hi
value = _cairo_uint128_add (value, half);
int64_t retval = value.hi;
retval = negative ? - retval : retval;
return retval;
}
/**
* Multiply this value by a Q0.128 value, presumably representing an inverse,
* completing a division operation.

View File

@@ -226,6 +226,29 @@ public:
return GetHighLow ().second;
}
/**
* Truncate to an integer.
* Truncation is always toward zero,
* \return The value truncated toward zero.
*/
int64_t GetInt (void) const
{
int64_t retval = static_cast<int64_t> (_v);
return retval;
}
/**
* Round to the nearest int.
* Similar to std::round this rounds halfway cases away from zero,
* regardless of the current (floating) rounding mode.
* \return The value rounded to the nearest int.
*/
int64_t Round (void) const
{
int64_t retval = std::round (_v);
return retval;
}
/**
* Multiply this value by a Q0.128 value, presumably representing an inverse,
* completing a division operation.

View File

@@ -187,6 +187,68 @@ Int64x64HiLoTestCase::DoRun (void)
}
class Int64x64IntRoundTestCase : public TestCase
{
public:
Int64x64IntRoundTestCase (void);
virtual void DoRun (void);
void Check (const int64x64_t value,
const int64_t expectInt,
const int64_t expectRnd);
};
Int64x64IntRoundTestCase::Int64x64IntRoundTestCase (void)
: TestCase ("Check GetInt and Round")
{}
void
Int64x64IntRoundTestCase::Check (const int64x64_t value,
const int64_t expectInt,
const int64_t expectRnd)
{
int64_t vInt = value.GetInt ();
int64_t vRnd = value.Round ();
bool pass = (vInt == expectInt) && (vRnd == expectRnd);
std::cout << GetParent ()->GetName () << " Check: "
<< (pass ? "pass " : "FAIL ")
<< value
<< " (int)-> " << std::setw (2) << vInt << " (expected: " << std::setw (2) << expectInt
<< "), (rnd)-> " << std::setw (2) << vRnd << " (expected " << std::setw (2) << expectRnd
<< ")"
<< std::endl;
NS_TEST_EXPECT_MSG_EQ (vInt, expectInt,
"Truncation to int failed");
NS_TEST_EXPECT_MSG_EQ (vRnd, expectRnd,
"Rounding to int failed.");
}
void
Int64x64IntRoundTestCase::DoRun (void)
{
std::cout << std::endl;
std::cout << GetParent ()->GetName () << " Check: " << GetName ()
<< std::endl;
// Trivial cases
Check ( 0, 0, 0);
Check ( 1, 1, 1);
Check (-1, -1, -1);
// Both should move toward zero
Check ( 2.4, 2, 2);
Check (-2.4, -2, -2);
// GetInt should move toward zero; Round should move away
Check ( 3.6, 3, 4);
Check (-3.6, -3, -4);
// Boundary case
Check ( 4.5, 4, 5);
Check (-4.5, -4, -5);
}
class Int64x64InputTestCase : public TestCase
{
public:
@@ -1224,6 +1286,7 @@ public:
{
AddTestCase (new Int64x64ImplTestCase (), TestCase::QUICK);
AddTestCase (new Int64x64HiLoTestCase (), TestCase::QUICK);
AddTestCase (new Int64x64IntRoundTestCase (), TestCase::QUICK);
AddTestCase (new Int64x64ArithmeticTestCase (), TestCase::QUICK);
AddTestCase (new Int64x64CompareTestCase (), TestCase::QUICK);
AddTestCase (new Int64x64InputTestCase (), TestCase::QUICK);