Support: Write ScaledNumbers::getLg{,Floor,Ceiling}()

llvm-svn: 211413
This commit is contained in:
Duncan P. N. Exon Smith 2014-06-20 22:33:40 +00:00
parent df100c337c
commit 818a8176ea
3 changed files with 157 additions and 33 deletions

View File

@ -67,16 +67,6 @@ public:
return IsNeg ? -int64_t(U) : int64_t(U);
}
static int32_t extractLg(const std::pair<int32_t, int> &Lg) {
return Lg.first;
}
static int32_t extractLgFloor(const std::pair<int32_t, int> &Lg) {
return Lg.first - (Lg.second > 0);
}
static int32_t extractLgCeiling(const std::pair<int32_t, int> &Lg) {
return Lg.first + (Lg.second < 0);
}
static int compare(uint64_t L, uint64_t R, int Shift) {
assert(Shift >= 0);
assert(Shift < 64);
@ -195,17 +185,21 @@ public:
/// \brief The log base 2, rounded.
///
/// Get the lg of the scalar. lg 0 is defined to be INT32_MIN.
int32_t lg() const { return extractLg(lgImpl()); }
int32_t lg() const { return ScaledNumbers::getLg(Digits, Exponent); }
/// \brief The log base 2, rounded towards INT32_MIN.
///
/// Get the lg floor. lg 0 is defined to be INT32_MIN.
int32_t lgFloor() const { return extractLgFloor(lgImpl()); }
int32_t lgFloor() const {
return ScaledNumbers::getLgFloor(Digits, Exponent);
}
/// \brief The log base 2, rounded towards INT32_MAX.
///
/// Get the lg ceiling. lg 0 is defined to be INT32_MIN.
int32_t lgCeiling() const { return extractLgCeiling(lgImpl()); }
int32_t lgCeiling() const {
return ScaledNumbers::getLgCeiling(Digits, Exponent);
}
bool operator==(const UnsignedFloat &X) const { return compare(X) == 0; }
bool operator<(const UnsignedFloat &X) const { return compare(X) < 0; }
@ -319,7 +313,6 @@ private:
return ScaledNumbers::getQuotient(Dividend, Divisor);
}
std::pair<int32_t, int> lgImpl() const;
static int countLeadingZerosWidth(DigitsType Digits) {
if (Width == 64)
return countLeadingZeros64(Digits);
@ -421,25 +414,6 @@ IntT UnsignedFloat<DigitsT>::toInt() const {
return N;
}
template <class DigitsT>
std::pair<int32_t, int> UnsignedFloat<DigitsT>::lgImpl() const {
if (isZero())
return std::make_pair(INT32_MIN, 0);
// Get the floor of the lg of Digits.
int32_t LocalFloor = Width - countLeadingZerosWidth(Digits) - 1;
// Get the floor of the lg of this.
int32_t Floor = Exponent + LocalFloor;
if (Digits == UINT64_C(1) << LocalFloor)
return std::make_pair(Floor, 0);
// Round based on the next digit.
assert(LocalFloor >= 1);
bool Round = Digits & UINT64_C(1) << (LocalFloor - 1);
return std::make_pair(Floor + Round, Round ? 1 : -1);
}
template <class DigitsT>
UnsignedFloat<DigitsT> UnsignedFloat<DigitsT>::matchExponents(UnsignedFloat X) {
if (isZero() || X.isZero() || Exponent == X.Exponent)

View File

@ -171,6 +171,62 @@ inline std::pair<uint64_t, int16_t> getQuotient64(uint64_t Dividend,
return getQuotient(Dividend, Divisor);
}
/// \brief Implementation of getLg() and friends.
///
/// Returns the rounded lg of \c Digits*2^Scale and an int specifying whether
/// this was rounded up (1), down (-1), or exact (0).
///
/// Returns \c INT32_MIN when \c Digits is zero.
template <class DigitsT>
inline std::pair<int32_t, int> getLgImpl(DigitsT Digits, int16_t Scale) {
static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
if (!Digits)
return std::make_pair(INT32_MIN, 0);
// Get the floor of the lg of Digits.
int32_t LocalFloor = sizeof(Digits) * 8 - countLeadingZeros(Digits) - 1;
// Get the actual floor.
int32_t Floor = Scale + LocalFloor;
if (Digits == UINT64_C(1) << LocalFloor)
return std::make_pair(Floor, 0);
// Round based on the next digit.
assert(LocalFloor >= 1);
bool Round = Digits & UINT64_C(1) << (LocalFloor - 1);
return std::make_pair(Floor + Round, Round ? 1 : -1);
}
/// \brief Get the lg (rounded) of a scaled number.
///
/// Get the lg of \c Digits*2^Scale.
///
/// Returns \c INT32_MIN when \c Digits is zero.
template <class DigitsT> int32_t getLg(DigitsT Digits, int16_t Scale) {
return getLgImpl(Digits, Scale).first;
}
/// \brief Get the lg floor of a scaled number.
///
/// Get the floor of the lg of \c Digits*2^Scale.
///
/// Returns \c INT32_MIN when \c Digits is zero.
template <class DigitsT> int32_t getLgFloor(DigitsT Digits, int16_t Scale) {
auto Lg = getLgImpl(Digits, Scale);
return Lg.first - (Lg.second > 0);
}
/// \brief Get the lg ceiling of a scaled number.
///
/// Get the ceiling of the lg of \c Digits*2^Scale.
///
/// Returns \c INT32_MIN when \c Digits is zero.
template <class DigitsT> int32_t getLgCeiling(DigitsT Digits, int16_t Scale) {
auto Lg = getLgImpl(Digits, Scale);
return Lg.first + (Lg.second < 0);
}
} // end namespace ScaledNumbers
} // end namespace llvm

View File

@ -191,4 +191,98 @@ TEST(PositiveFloatTest, Divide) {
EXPECT_EQ(SP64(0xd555555555555555, -63), getQuotient64(5, 3));
}
TEST(ScaledNumbersHelpersTest, getLg) {
EXPECT_EQ(0, getLg(UINT32_C(1), 0));
EXPECT_EQ(1, getLg(UINT32_C(1), 1));
EXPECT_EQ(1, getLg(UINT32_C(2), 0));
EXPECT_EQ(3, getLg(UINT32_C(1), 3));
EXPECT_EQ(3, getLg(UINT32_C(7), 0));
EXPECT_EQ(3, getLg(UINT32_C(8), 0));
EXPECT_EQ(3, getLg(UINT32_C(9), 0));
EXPECT_EQ(3, getLg(UINT32_C(64), -3));
EXPECT_EQ(31, getLg((UINT32_MAX >> 1) + 2, 0));
EXPECT_EQ(32, getLg(UINT32_MAX, 0));
EXPECT_EQ(-1, getLg(UINT32_C(1), -1));
EXPECT_EQ(-1, getLg(UINT32_C(2), -2));
EXPECT_EQ(INT32_MIN, getLg(UINT32_C(0), -1));
EXPECT_EQ(INT32_MIN, getLg(UINT32_C(0), 0));
EXPECT_EQ(INT32_MIN, getLg(UINT32_C(0), 1));
EXPECT_EQ(0, getLg(UINT64_C(1), 0));
EXPECT_EQ(1, getLg(UINT64_C(1), 1));
EXPECT_EQ(1, getLg(UINT64_C(2), 0));
EXPECT_EQ(3, getLg(UINT64_C(1), 3));
EXPECT_EQ(3, getLg(UINT64_C(7), 0));
EXPECT_EQ(3, getLg(UINT64_C(8), 0));
EXPECT_EQ(3, getLg(UINT64_C(9), 0));
EXPECT_EQ(3, getLg(UINT64_C(64), -3));
EXPECT_EQ(63, getLg((UINT64_MAX >> 1) + 2, 0));
EXPECT_EQ(64, getLg(UINT64_MAX, 0));
EXPECT_EQ(-1, getLg(UINT64_C(1), -1));
EXPECT_EQ(-1, getLg(UINT64_C(2), -2));
EXPECT_EQ(INT32_MIN, getLg(UINT64_C(0), -1));
EXPECT_EQ(INT32_MIN, getLg(UINT64_C(0), 0));
EXPECT_EQ(INT32_MIN, getLg(UINT64_C(0), 1));
}
TEST(ScaledNumbersHelpersTest, getLgFloor) {
EXPECT_EQ(0, getLgFloor(UINT32_C(1), 0));
EXPECT_EQ(1, getLgFloor(UINT32_C(1), 1));
EXPECT_EQ(1, getLgFloor(UINT32_C(2), 0));
EXPECT_EQ(2, getLgFloor(UINT32_C(7), 0));
EXPECT_EQ(3, getLgFloor(UINT32_C(1), 3));
EXPECT_EQ(3, getLgFloor(UINT32_C(8), 0));
EXPECT_EQ(3, getLgFloor(UINT32_C(9), 0));
EXPECT_EQ(3, getLgFloor(UINT32_C(64), -3));
EXPECT_EQ(31, getLgFloor((UINT32_MAX >> 1) + 2, 0));
EXPECT_EQ(31, getLgFloor(UINT32_MAX, 0));
EXPECT_EQ(INT32_MIN, getLgFloor(UINT32_C(0), -1));
EXPECT_EQ(INT32_MIN, getLgFloor(UINT32_C(0), 0));
EXPECT_EQ(INT32_MIN, getLgFloor(UINT32_C(0), 1));
EXPECT_EQ(0, getLgFloor(UINT64_C(1), 0));
EXPECT_EQ(1, getLgFloor(UINT64_C(1), 1));
EXPECT_EQ(1, getLgFloor(UINT64_C(2), 0));
EXPECT_EQ(2, getLgFloor(UINT64_C(7), 0));
EXPECT_EQ(3, getLgFloor(UINT64_C(1), 3));
EXPECT_EQ(3, getLgFloor(UINT64_C(8), 0));
EXPECT_EQ(3, getLgFloor(UINT64_C(9), 0));
EXPECT_EQ(3, getLgFloor(UINT64_C(64), -3));
EXPECT_EQ(63, getLgFloor((UINT64_MAX >> 1) + 2, 0));
EXPECT_EQ(63, getLgFloor(UINT64_MAX, 0));
EXPECT_EQ(INT32_MIN, getLgFloor(UINT64_C(0), -1));
EXPECT_EQ(INT32_MIN, getLgFloor(UINT64_C(0), 0));
EXPECT_EQ(INT32_MIN, getLgFloor(UINT64_C(0), 1));
}
TEST(ScaledNumbersHelpersTest, getLgCeiling) {
EXPECT_EQ(0, getLgCeiling(UINT32_C(1), 0));
EXPECT_EQ(1, getLgCeiling(UINT32_C(1), 1));
EXPECT_EQ(1, getLgCeiling(UINT32_C(2), 0));
EXPECT_EQ(3, getLgCeiling(UINT32_C(1), 3));
EXPECT_EQ(3, getLgCeiling(UINT32_C(7), 0));
EXPECT_EQ(3, getLgCeiling(UINT32_C(8), 0));
EXPECT_EQ(3, getLgCeiling(UINT32_C(64), -3));
EXPECT_EQ(4, getLgCeiling(UINT32_C(9), 0));
EXPECT_EQ(32, getLgCeiling(UINT32_MAX, 0));
EXPECT_EQ(32, getLgCeiling((UINT32_MAX >> 1) + 2, 0));
EXPECT_EQ(INT32_MIN, getLgCeiling(UINT32_C(0), -1));
EXPECT_EQ(INT32_MIN, getLgCeiling(UINT32_C(0), 0));
EXPECT_EQ(INT32_MIN, getLgCeiling(UINT32_C(0), 1));
EXPECT_EQ(0, getLgCeiling(UINT64_C(1), 0));
EXPECT_EQ(1, getLgCeiling(UINT64_C(1), 1));
EXPECT_EQ(1, getLgCeiling(UINT64_C(2), 0));
EXPECT_EQ(3, getLgCeiling(UINT64_C(1), 3));
EXPECT_EQ(3, getLgCeiling(UINT64_C(7), 0));
EXPECT_EQ(3, getLgCeiling(UINT64_C(8), 0));
EXPECT_EQ(3, getLgCeiling(UINT64_C(64), -3));
EXPECT_EQ(4, getLgCeiling(UINT64_C(9), 0));
EXPECT_EQ(64, getLgCeiling((UINT64_MAX >> 1) + 2, 0));
EXPECT_EQ(64, getLgCeiling(UINT64_MAX, 0));
EXPECT_EQ(INT32_MIN, getLgCeiling(UINT64_C(0), -1));
EXPECT_EQ(INT32_MIN, getLgCeiling(UINT64_C(0), 0));
EXPECT_EQ(INT32_MIN, getLgCeiling(UINT64_C(0), 1));
}
} // end namespace