Implement QofInt128::gcd and lcm.

This commit is contained in:
John Ralls 2014-11-19 10:36:00 -08:00
parent 765d5583c1
commit f5c7b1101d
3 changed files with 74 additions and 2 deletions

View File

@ -68,7 +68,7 @@ QofInt128::QofInt128 (int64_t upper, int64_t lower, unsigned char flags) :
m_hi >>= 1;
}
QofInt128::QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags) :
QofInt128::QofInt128 (uint64_t upper, uint64_t lower, unsigned char flags) :
m_flags {flags}, m_hi {upper},
m_lo {lower} {}
@ -124,6 +124,55 @@ QofInt128::cmp (const QofInt128& b) const noexcept
return 0;
}
/* Knuth 4.5.3 Algo B, recommended by GMP as much faster than Algo A (Euclidean
* method).
*/
QofInt128
QofInt128::gcd(QofInt128 b) const noexcept
{
if (b.isZero())
return *this;
if (isZero())
return b;
if (b.isOverflow() || b.isNan())
return b;
if (isOverflow() || isNan())
return *this;
QofInt128 a (isNeg() ? -(*this) : *this);
if (b.isNeg()) b = -b;
uint k {};
const uint64_t one {1};
while (!((a & one) || (b & one))) //B1
{
a >>= 1;
b >>= 1;
++k;
}
QofInt128 t {a & one ? -b : a}; //B2
while (a != b)
{
while (t && (t & one ^ one)) t >>= 1; //B3 & B4
if (t.isNeg()) //B5
b = -t;
else
a = t;
t = a - b; //B6
}
return a << k;
}
/* Since u * v = gcd(u, v) * lcm(u, v), we find lcm by u / gcd * v. */
QofInt128
QofInt128::lcm(const QofInt128& b) const noexcept
{
auto common = gcd(b);
return *this / common * b;
}
bool
QofInt128::isNeg () const noexcept
{

View File

@ -114,7 +114,7 @@ enum // Values for m_flags
*
* @return A QofInt128 having the GCD.
*/
QofInt128 gcd (const QofInt128& b) const noexcept;
QofInt128 gcd (QofInt128 b) const noexcept;
/**
* Computes the Least Common Multiple between the object and parameter
*

View File

@ -388,3 +388,26 @@ TEST(qofint128_functions, divide)
EXPECT_EQ (big, big %= bigger);
EXPECT_EQ (two, bigger /= big);
}
TEST(qofint128_functions, GCD)
{
int64_t barg {INT64_C(4878849681579065407)};
int64_t sarg {INT64_C(4344522355275710401)};
uint64_t uarg {UINT64_C(13567894392130486208)};
QofInt128 one (INT64_C(1));
QofInt128 smallest (sarg);
QofInt128 smaller (barg);
QofInt128 small (uarg);
QofInt128 big = smaller * smallest;
QofInt128 bigger = small * smaller;
EXPECT_EQ (smaller, big.gcd(smaller));
EXPECT_EQ (smallest, big.gcd(smallest));
EXPECT_EQ (small, bigger.gcd(small));
EXPECT_EQ (smaller, bigger.gcd(smaller));
EXPECT_EQ (one, big.gcd (small));
EXPECT_EQ (one, bigger.gcd (smallest));
EXPECT_EQ (big, smaller.lcm (smallest));
}