mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Replace GncInt128’s flags variable with bit-stuffing in the high leg.
Loses three bits so GncInt128 becomes really a GncInt125, but we don’t really need the single order-of-magnitude: 10**38 is big enough. Saves a full word of memory for each GncInt128, which means 2 words for GncRational. That’s a 33% saving in memory for 64-bit and makes the object size the same (32 bytes) for all architectures.
This commit is contained in:
parent
c633e80a24
commit
0403a6667a
@ -32,6 +32,7 @@ extern "C"
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
|
||||
/* All algorithms from Donald E. Knuth, "The Art of Computer
|
||||
* Programming, Volume 2: Seminumerical Algorithms", 3rd Ed.,
|
||||
@ -42,13 +43,29 @@ namespace {
|
||||
static const unsigned int sublegs = GncInt128::numlegs * 2;
|
||||
static const unsigned int sublegbits = GncInt128::legbits / 2;
|
||||
static const uint64_t sublegmask = (UINT64_C(1) << sublegbits) - 1;
|
||||
static const uint64_t flagmask = UINT64_C(0xe000000000000000);
|
||||
static const uint64_t nummask = UINT64_C(0x1fffffffffffffff);
|
||||
/* Assumes that the high bits represent old flags to be replaced.
|
||||
* Any overflow must be detected first!
|
||||
*/
|
||||
static inline uint64_t set_flags(uint64_t leg, uint8_t flags)
|
||||
{
|
||||
auto flag_part = static_cast<uint64_t>(flags) << 61;
|
||||
return flag_part + (leg & nummask);
|
||||
}
|
||||
static inline uint8_t get_flags(uint64_t leg)
|
||||
{
|
||||
return (leg & flagmask) >> 61;
|
||||
}
|
||||
static inline uint64_t get_num(uint64_t leg)
|
||||
{
|
||||
return leg & nummask;
|
||||
}
|
||||
}
|
||||
|
||||
GncInt128::GncInt128 () : m_flags {}, m_hi {0}, m_lo {0}{}
|
||||
GncInt128::GncInt128 () : m_hi {0}, m_lo {0}{}
|
||||
|
||||
GncInt128::GncInt128 (int64_t upper, int64_t lower, unsigned char flags) :
|
||||
m_flags {static_cast<unsigned char>(flags ^ (upper < 0 ? neg :
|
||||
upper == 0 && lower < 0 ? neg : pos))},
|
||||
GncInt128::GncInt128 (int64_t upper, int64_t lower, uint8_t flags) :
|
||||
m_hi {static_cast<uint64_t>(upper < 0 ? -upper : upper)},
|
||||
m_lo {static_cast<uint64_t>(lower < 0 ? -lower : lower)}
|
||||
{
|
||||
@ -58,38 +75,75 @@ GncInt128::GncInt128 (int64_t upper, int64_t lower, unsigned char flags) :
|
||||
m_lo += (m_hi << 63);
|
||||
|
||||
m_hi >>= 1;
|
||||
if (m_hi & flagmask)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Constructing GncInt128 with int64_t " << upper
|
||||
<< " which is too big.";
|
||||
throw std::overflow_error(ss.str());
|
||||
}
|
||||
flags ^= (upper < 0 ? neg : upper == 0 && lower < 0 ? neg : pos);
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
}
|
||||
|
||||
GncInt128::GncInt128 (int64_t upper, uint64_t lower, unsigned char flags) :
|
||||
m_flags {static_cast<unsigned char>(flags ^ (upper < 0 ? neg : pos))},
|
||||
m_hi {static_cast<uint64_t>(upper < 0 ? -upper : upper)}, m_lo {lower} {}
|
||||
GncInt128::GncInt128 (int64_t upper, uint64_t lower, uint8_t flags) :
|
||||
m_hi {static_cast<uint64_t>(upper < 0 ? -upper : upper)}, m_lo {lower}
|
||||
{
|
||||
if (m_hi & flagmask)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Constructing GncInt128 with int64_t " << upper
|
||||
<< " which is too big when lower is unsigned.";
|
||||
throw std::overflow_error(ss.str());
|
||||
}
|
||||
flags ^= (upper < 0 ? neg : pos);
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
}
|
||||
|
||||
GncInt128::GncInt128 (uint64_t upper, uint64_t lower, unsigned char flags) :
|
||||
m_flags {flags}, m_hi {upper}, m_lo {lower} {}
|
||||
GncInt128::GncInt128 (uint64_t upper, uint64_t lower, uint8_t flags) :
|
||||
m_hi {upper}, m_lo {lower}
|
||||
{
|
||||
/* somewhere in the bowels of gnc_module.scm compilation this gets called
|
||||
* with upper=INT64_MAX, which would otherwise throw. Make it our max value
|
||||
* instead.
|
||||
*/
|
||||
if (m_hi == UINT64_MAX)
|
||||
m_hi = nummask;
|
||||
if (m_hi & flagmask)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Constructing GncInt128 with uint64_t " << upper
|
||||
<< " which is too big.";
|
||||
throw std::overflow_error(ss.str());
|
||||
}
|
||||
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
}
|
||||
|
||||
GncInt128&
|
||||
GncInt128::zero () noexcept
|
||||
{
|
||||
m_flags = 0;
|
||||
m_lo = m_hi = UINT64_C(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
GncInt128::operator int64_t() const
|
||||
{
|
||||
if ((m_flags & neg) && isBig())
|
||||
auto flags = get_flags(m_hi);
|
||||
if ((flags & neg) && isBig())
|
||||
throw std::underflow_error ("Negative value too large to represent as int64_t");
|
||||
if ((m_flags & (overflow | NaN)) || isBig())
|
||||
if ((flags & (overflow | NaN)) || isBig())
|
||||
throw std::overflow_error ("Value too large to represent as int64_t");
|
||||
int64_t retval = static_cast<int64_t>(m_lo);
|
||||
return m_flags & neg ? -retval : retval;
|
||||
return flags & neg ? -retval : retval;
|
||||
}
|
||||
|
||||
GncInt128::operator uint64_t() const
|
||||
{
|
||||
if (m_flags & neg)
|
||||
auto flags = get_flags(m_hi);
|
||||
if (flags & neg)
|
||||
throw std::underflow_error ("Can't represent negative value as uint64_t");
|
||||
if ((m_flags & (overflow | NaN)) || (m_hi || m_lo > UINT64_MAX))
|
||||
if ((flags & (overflow | NaN)) || (m_hi || m_lo > UINT64_MAX))
|
||||
throw std::overflow_error ("Value to large to represent as uint64_t");
|
||||
return m_lo;
|
||||
}
|
||||
@ -98,22 +152,25 @@ GncInt128::operator uint64_t() const
|
||||
int
|
||||
GncInt128::cmp (const GncInt128& b) const noexcept
|
||||
{
|
||||
if (m_flags & (overflow | NaN))
|
||||
auto flags = get_flags(m_hi);
|
||||
if (flags & (overflow | NaN))
|
||||
return -1;
|
||||
if (b.isOverflow () || b.isNan ())
|
||||
return 1;
|
||||
if (m_flags & neg)
|
||||
auto hi = get_num(m_hi);
|
||||
auto bhi = get_num(b.m_hi);
|
||||
if (flags & neg)
|
||||
{
|
||||
if (!b.isNeg()) return -1;
|
||||
if (m_hi > b.m_hi) return -1;
|
||||
if (m_hi < b.m_hi) return 1;
|
||||
if (hi > bhi) return -1;
|
||||
if (hi < bhi) return 1;
|
||||
if (m_lo > b.m_lo) return -1;
|
||||
if (m_lo < b.m_lo) return 1;
|
||||
return 0;
|
||||
}
|
||||
if (b.isNeg()) return 1;
|
||||
if (m_hi < b.m_hi) return -1;
|
||||
if (m_hi > b.m_hi) return 1;
|
||||
if (hi < bhi) return -1;
|
||||
if (hi > bhi) return 1;
|
||||
if (m_lo < b.m_lo) return -1;
|
||||
if (m_lo > b.m_lo) return 1;
|
||||
return 0;
|
||||
@ -190,37 +247,38 @@ GncInt128::pow(unsigned int b) const noexcept
|
||||
bool
|
||||
GncInt128::isNeg () const noexcept
|
||||
{
|
||||
return (m_flags & neg);
|
||||
return (get_flags(m_hi) & neg);
|
||||
}
|
||||
|
||||
bool
|
||||
GncInt128::isBig () const noexcept
|
||||
{
|
||||
return (m_hi || m_lo > INT64_MAX);
|
||||
return (get_num(m_hi) || m_lo > INT64_MAX);
|
||||
}
|
||||
|
||||
bool
|
||||
GncInt128::isOverflow () const noexcept
|
||||
{
|
||||
return (m_flags & overflow);
|
||||
return (get_flags(m_hi) & overflow);
|
||||
}
|
||||
|
||||
bool
|
||||
GncInt128::isNan () const noexcept
|
||||
{
|
||||
return (m_flags & NaN);
|
||||
return (get_flags(m_hi) & NaN);
|
||||
}
|
||||
|
||||
bool
|
||||
GncInt128::valid() const noexcept
|
||||
{
|
||||
return !(m_flags & (overflow | NaN));
|
||||
return !(get_flags(m_hi) & (overflow | NaN));
|
||||
}
|
||||
|
||||
bool
|
||||
GncInt128::isZero() const noexcept
|
||||
{
|
||||
return ((m_flags & (overflow | NaN)) == 0 && m_hi == 0 && m_lo == 0);
|
||||
return ((get_flags(m_hi) & (overflow | NaN)) == 0 &&
|
||||
get_num(m_hi) == 0 && m_lo == 0);
|
||||
}
|
||||
|
||||
GncInt128
|
||||
@ -235,8 +293,9 @@ GncInt128::abs() const noexcept
|
||||
unsigned int
|
||||
GncInt128::bits() const noexcept
|
||||
{
|
||||
unsigned int bits {static_cast<unsigned int>(m_hi == 0 ? 0 : 64)};
|
||||
uint64_t temp {(m_hi == 0 ? m_lo : m_hi)};
|
||||
auto hi = get_num(m_hi);
|
||||
unsigned int bits {static_cast<unsigned int>(hi == 0 ? 0 : 64)};
|
||||
uint64_t temp {(hi == 0 ? m_lo : hi)};
|
||||
for (;temp > 0; temp >>= 1)
|
||||
++bits;
|
||||
return bits;
|
||||
@ -247,10 +306,12 @@ GncInt128
|
||||
GncInt128::operator-() const noexcept
|
||||
{
|
||||
auto retval = *this;
|
||||
auto flags = get_flags(retval.m_hi);
|
||||
if (isNeg())
|
||||
retval.m_flags ^= neg;
|
||||
flags ^= neg;
|
||||
else
|
||||
retval.m_flags |= neg;
|
||||
flags |= neg;
|
||||
retval.m_hi = set_flags(retval.m_hi, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -286,11 +347,12 @@ GncInt128::operator-- (int) noexcept
|
||||
GncInt128&
|
||||
GncInt128::operator+= (const GncInt128& b) noexcept
|
||||
{
|
||||
auto flags = get_flags(m_hi);
|
||||
if (b.isOverflow())
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
if (b.isNan())
|
||||
m_flags |= NaN;
|
||||
|
||||
flags |= NaN;
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
if (isOverflow() || isNan())
|
||||
return *this;
|
||||
if ((isNeg () && !b.isNeg ()) || (!isNeg () && b.isNeg ()))
|
||||
@ -298,32 +360,38 @@ GncInt128::operator+= (const GncInt128& b) noexcept
|
||||
uint64_t result = m_lo + b.m_lo;
|
||||
uint64_t carry = static_cast<int64_t>(result < m_lo); //Wrapping
|
||||
m_lo = result;
|
||||
result = m_hi + b.m_hi + carry;
|
||||
if (result < m_hi)
|
||||
m_flags |= overflow;
|
||||
m_hi = result;
|
||||
auto hi = get_num(m_hi);
|
||||
auto bhi = get_num(b.m_hi);
|
||||
result = hi + bhi + carry;
|
||||
if (result < hi || result & flagmask)
|
||||
flags |= overflow;
|
||||
m_hi = set_flags(result, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
GncInt128&
|
||||
GncInt128::operator<<= (unsigned int i) noexcept
|
||||
{
|
||||
auto flags = get_flags(m_hi);
|
||||
if (i > maxbits)
|
||||
{
|
||||
m_flags &= 0xfe;
|
||||
m_hi = 0;
|
||||
flags &= 0xfe;
|
||||
m_hi = set_flags(0, flags);
|
||||
m_lo = 0;
|
||||
return *this;
|
||||
}
|
||||
auto hi = get_num(m_hi);
|
||||
if (i < legbits)
|
||||
{
|
||||
uint64_t carry {(m_lo & (((UINT64_C(1) << i) - 1) << (legbits - i)))};
|
||||
m_lo <<= i;
|
||||
m_hi <<= i;
|
||||
m_hi += carry;
|
||||
hi <<= i;
|
||||
hi += carry;
|
||||
m_hi = set_flags(hi, flags);
|
||||
return *this;
|
||||
}
|
||||
m_hi = m_lo << (i - legbits);
|
||||
hi = m_lo << (i - legbits);
|
||||
m_hi = set_flags(hi, flags);
|
||||
m_lo = 0;
|
||||
return *this;
|
||||
}
|
||||
@ -331,33 +399,38 @@ GncInt128::operator<<= (unsigned int i) noexcept
|
||||
GncInt128&
|
||||
GncInt128::operator>>= (unsigned int i) noexcept
|
||||
{
|
||||
auto flags = get_flags(m_hi);
|
||||
if (i > maxbits)
|
||||
{
|
||||
m_flags &= 0xfe;
|
||||
m_hi = 0;
|
||||
flags &= 0xfe;
|
||||
m_hi = set_flags(0, flags);
|
||||
m_lo = 0;
|
||||
return *this;
|
||||
}
|
||||
auto hi = get_num(m_hi);
|
||||
if (i < legbits)
|
||||
{
|
||||
uint64_t carry {(m_hi & ((UINT64_C(1) << i) - 1))};
|
||||
uint64_t carry {(hi & ((UINT64_C(1) << i) - 1))};
|
||||
m_lo >>= i;
|
||||
m_hi >>= i;
|
||||
hi >>= i;
|
||||
m_lo += (carry << (legbits - i));
|
||||
m_hi = set_flags(hi, flags);
|
||||
return *this;
|
||||
}
|
||||
m_lo = m_hi >> (i - legbits);
|
||||
m_hi = 0;
|
||||
m_lo = hi >> (i - legbits);
|
||||
m_hi = set_flags(0, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
GncInt128&
|
||||
GncInt128::operator-= (const GncInt128& b) noexcept
|
||||
{
|
||||
auto flags = get_flags(m_hi);
|
||||
if (b.isOverflow())
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
if (b.isNan())
|
||||
m_flags |= NaN;
|
||||
flags |= NaN;
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
|
||||
if (isOverflow() || isNan())
|
||||
return *this;
|
||||
@ -365,10 +438,11 @@ GncInt128::operator-= (const GncInt128& b) noexcept
|
||||
if ((!isNeg() && b.isNeg()) || (isNeg() && !b.isNeg()))
|
||||
return this->operator+= (-b);
|
||||
bool operand_bigger {abs().cmp (b.abs()) < 0};
|
||||
auto hi = get_num(m_hi);
|
||||
auto far_hi = get_num(b.m_hi);
|
||||
if (operand_bigger)
|
||||
{
|
||||
m_flags ^= neg; // ^= flips the bit
|
||||
uint64_t far_hi {b.m_hi};
|
||||
flags ^= neg; // ^= flips the bit
|
||||
if (m_lo > b.m_lo)
|
||||
{
|
||||
/* The + 1 on the end is because we really want to use 2^64, or
|
||||
@ -379,20 +453,20 @@ GncInt128::operator-= (const GncInt128& b) noexcept
|
||||
}
|
||||
else
|
||||
m_lo = b.m_lo - m_lo;
|
||||
|
||||
m_hi = far_hi - m_hi;
|
||||
hi = far_hi - hi;
|
||||
m_hi = set_flags(hi, flags);
|
||||
return *this;
|
||||
}
|
||||
if (m_lo < b.m_lo)
|
||||
{
|
||||
m_lo = UINT64_MAX - b.m_lo + m_lo + 1; //See UINT64_MAX comment above
|
||||
--m_hi; //borrow
|
||||
--hi; //borrow
|
||||
}
|
||||
else
|
||||
m_lo -= b.m_lo;
|
||||
|
||||
m_hi -= b.m_hi;
|
||||
|
||||
hi -= far_hi;
|
||||
m_hi = set_flags(hi, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -400,38 +474,45 @@ GncInt128&
|
||||
GncInt128::operator*= (const GncInt128& b) noexcept
|
||||
{
|
||||
/* Test for 0 first */
|
||||
auto flags = get_flags(m_hi);
|
||||
if (isZero() || b.isZero())
|
||||
{
|
||||
m_hi = m_lo = 0;
|
||||
m_lo = 0;
|
||||
m_hi = set_flags(0, flags);
|
||||
return *this;
|
||||
}
|
||||
if (b.isOverflow())
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
if (b.isNan())
|
||||
m_flags |= NaN;
|
||||
|
||||
flags |= NaN;
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
if (isOverflow() || isNan())
|
||||
return *this;
|
||||
|
||||
/* Test for overflow before spending time on the calculation */
|
||||
if (m_hi && b.m_hi)
|
||||
auto hi = get_num(m_hi);
|
||||
auto bhi = get_num(b.m_hi);
|
||||
if (hi && bhi)
|
||||
{
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
m_hi = set_flags(hi, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned int abits {bits()}, bbits {b.bits()};
|
||||
if (abits + bbits > maxbits)
|
||||
{
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
return *this;
|
||||
}
|
||||
/* Handle the sign; ^ flips if b is negative */
|
||||
m_flags ^= (b.m_flags & neg);
|
||||
flags ^= (get_flags(b.m_hi) & neg);
|
||||
/* The trivial case */
|
||||
if (abits + bbits <= legbits)
|
||||
{
|
||||
m_lo *= b.m_lo;
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -448,9 +529,9 @@ GncInt128::operator*= (const GncInt128& b) noexcept
|
||||
*/
|
||||
|
||||
uint64_t av[sublegs] {(m_lo & sublegmask), (m_lo >> sublegbits),
|
||||
(m_hi & sublegmask), (m_hi >> sublegbits)};
|
||||
(hi & sublegmask), (hi >> sublegbits)};
|
||||
uint64_t bv[sublegs] {(b.m_lo & sublegmask), (b.m_lo >> sublegbits),
|
||||
(b.m_hi & sublegmask), (b.m_hi >> sublegbits)};
|
||||
(bhi & sublegmask), (bhi >> sublegbits)};
|
||||
uint64_t rv[sublegs] {};
|
||||
uint64_t carry {}, scratch {};
|
||||
|
||||
@ -478,19 +559,23 @@ GncInt128::operator*= (const GncInt128& b) noexcept
|
||||
|
||||
if (carry) //Shouldn't happen because of the checks above
|
||||
{
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
m_lo = rv[0] + (rv[1] << sublegbits);
|
||||
carry = rv[1] >> sublegbits;
|
||||
carry += (rv[1] << sublegbits) > m_lo || rv[0] > m_lo ? 1 : 0;
|
||||
m_hi = rv[2] + (rv[3] << sublegbits) + carry;
|
||||
if ((rv[3] << sublegbits) > m_hi || rv[2] > m_hi || (rv[3] >> sublegbits))
|
||||
hi = rv[2] + (rv[3] << sublegbits) + carry;
|
||||
if ((rv[3] << sublegbits) > hi || rv[2] > hi || (rv[3] >> sublegbits) ||
|
||||
hi & flagmask)
|
||||
{
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
m_hi = set_flags(hi, flags);
|
||||
return *this;
|
||||
}
|
||||
m_hi = set_flags(hi, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -501,7 +586,8 @@ namespace {
|
||||
*/
|
||||
/* We're using arrays here instead of vectors to avoid an alloc. */
|
||||
void
|
||||
div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n, GncInt128& q, GncInt128& r) noexcept
|
||||
div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n,
|
||||
GncInt128& q, GncInt128& r) noexcept
|
||||
{
|
||||
/* D1, Normalization */
|
||||
uint64_t qv[sublegs] {};
|
||||
@ -598,7 +684,8 @@ div_multi_leg (uint64_t* u, size_t m, uint64_t* v, size_t n, GncInt128& q, GncIn
|
||||
}
|
||||
|
||||
void
|
||||
div_single_leg (uint64_t* u, size_t m, uint64_t v, GncInt128& q, GncInt128& r) noexcept
|
||||
div_single_leg (uint64_t* u, size_t m, uint64_t v,
|
||||
GncInt128& q, GncInt128& r) noexcept
|
||||
{
|
||||
uint64_t qv[sublegs] {};
|
||||
uint64_t carry {};
|
||||
@ -625,17 +712,23 @@ div_single_leg (uint64_t* u, size_t m, uint64_t v, GncInt128& q, GncInt128& r) n
|
||||
void
|
||||
GncInt128::div (const GncInt128& b, GncInt128& q, GncInt128& r) const noexcept
|
||||
{
|
||||
auto qflags = get_flags(q.m_hi);
|
||||
auto rflags = get_flags(r.m_hi);
|
||||
if (isOverflow() || b.isOverflow())
|
||||
{
|
||||
q.m_flags |= overflow;
|
||||
r.m_flags |= overflow;
|
||||
qflags |= overflow;
|
||||
rflags |= overflow;
|
||||
q.m_hi = set_flags(q.m_hi, qflags);
|
||||
r.m_hi = set_flags(r.m_hi, rflags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNan() || b.isNan())
|
||||
{
|
||||
q.m_flags |= NaN;
|
||||
r.m_flags |= NaN;
|
||||
qflags |= NaN;
|
||||
rflags |= NaN;
|
||||
q.m_hi = set_flags(q.m_hi, qflags);
|
||||
r.m_hi = set_flags(r.m_hi, rflags);
|
||||
return;
|
||||
}
|
||||
assert (&q != this);
|
||||
@ -646,23 +739,28 @@ GncInt128::div (const GncInt128& b, GncInt128& q, GncInt128& r) const noexcept
|
||||
q.zero(), r.zero();
|
||||
if (b.isZero())
|
||||
{
|
||||
q.m_flags |= NaN;
|
||||
r.m_flags |= NaN;
|
||||
qflags |= NaN;
|
||||
rflags |= NaN;
|
||||
q.m_hi = set_flags(q.m_hi, qflags);
|
||||
r.m_hi = set_flags(r.m_hi, rflags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNeg())
|
||||
q.m_flags |= neg;
|
||||
qflags |= neg;
|
||||
|
||||
if (b.isNeg())
|
||||
q.m_flags ^= neg;
|
||||
qflags ^= neg;
|
||||
|
||||
if (abs() < b.abs())
|
||||
{
|
||||
r = *this;
|
||||
return;
|
||||
}
|
||||
if (m_hi == 0 && b.m_hi == 0) //let the hardware do it
|
||||
auto hi = get_num(m_hi);
|
||||
auto bhi = get_num(b.m_hi);
|
||||
q.m_hi = set_flags(hi, qflags);
|
||||
if (hi == 0 && bhi == 0) //let the hardware do it
|
||||
{
|
||||
q.m_lo = m_lo / b.m_lo;
|
||||
r.m_lo = m_lo % b.m_lo;
|
||||
@ -670,9 +768,9 @@ GncInt128::div (const GncInt128& b, GncInt128& q, GncInt128& r) const noexcept
|
||||
}
|
||||
|
||||
uint64_t u[sublegs + 2] {(m_lo & sublegmask), (m_lo >> sublegbits),
|
||||
(m_hi & sublegmask), (m_hi >> sublegbits), 0, 0};
|
||||
(hi & sublegmask), (hi >> sublegbits), 0, 0};
|
||||
uint64_t v[sublegs] {(b.m_lo & sublegmask), (b.m_lo >> sublegbits),
|
||||
(b.m_hi & sublegmask), (b.m_hi >> sublegbits)};
|
||||
(bhi & sublegmask), (bhi >> sublegbits)};
|
||||
auto m = u[3] ? 4 : u[2] ? 3 : u[1] ? 2 : u[0] ? 1 : 0;
|
||||
auto n = v[3] ? 4 : v[2] ? 3 : v[1] ? 2 : v[0] ? 1 : 0;
|
||||
if (m == 0 || n == 0) //Shouldn't happen
|
||||
@ -699,30 +797,35 @@ GncInt128::operator%= (const GncInt128& b) noexcept
|
||||
div(b, q, r);
|
||||
std::swap (*this, r);
|
||||
if (q.isNan())
|
||||
m_flags |= NaN;
|
||||
m_hi = set_flags(m_hi, (get_flags(m_hi) | NaN));
|
||||
return *this;
|
||||
}
|
||||
|
||||
GncInt128&
|
||||
GncInt128::operator&= (const GncInt128& b) noexcept
|
||||
{
|
||||
auto flags = get_flags(m_hi);
|
||||
if (b.isOverflow())
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
if (b.isNan())
|
||||
m_flags |= NaN;
|
||||
|
||||
flags |= NaN;
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
if (isOverflow() || isNan())
|
||||
return *this;
|
||||
|
||||
m_hi &= b.m_hi;
|
||||
auto hi = get_num(m_hi);
|
||||
hi &= get_num(b.m_hi);
|
||||
m_lo &= b.m_lo;
|
||||
m_hi = set_flags(hi, flags);
|
||||
return *this;
|
||||
}
|
||||
|
||||
GncInt128&
|
||||
GncInt128::operator|= (const GncInt128& b) noexcept
|
||||
{
|
||||
m_hi ^= b.m_hi;
|
||||
auto flags = get_flags(m_hi);
|
||||
auto hi = get_num(m_hi);
|
||||
hi ^= get_num(b.m_hi);
|
||||
m_hi = set_flags(hi, flags);
|
||||
m_lo ^= b.m_lo;
|
||||
return *this;
|
||||
}
|
||||
@ -730,15 +833,17 @@ GncInt128::operator|= (const GncInt128& b) noexcept
|
||||
GncInt128&
|
||||
GncInt128::operator^= (const GncInt128& b) noexcept
|
||||
{
|
||||
auto flags = get_flags(m_hi);
|
||||
if (b.isOverflow())
|
||||
m_flags |= overflow;
|
||||
flags |= overflow;
|
||||
if (b.isNan())
|
||||
m_flags |= NaN;
|
||||
|
||||
flags |= NaN;
|
||||
m_hi = set_flags(m_hi, flags);
|
||||
if (isOverflow() || isNan())
|
||||
return *this;
|
||||
|
||||
m_hi ^= b.m_hi;
|
||||
auto hi = get_num(m_hi);
|
||||
hi ^= get_num(b.m_hi);
|
||||
m_hi = set_flags(hi, flags);
|
||||
m_lo ^= b.m_lo;
|
||||
return *this;
|
||||
}
|
||||
@ -801,7 +906,7 @@ GncInt128::asCharBufR(char* buf) const noexcept
|
||||
return buf;
|
||||
}
|
||||
uint64_t d[dec_array_size] {};
|
||||
decimal_from_binary(d, m_hi, m_lo);
|
||||
decimal_from_binary(d, get_num(m_hi), m_lo);
|
||||
char* next = buf;
|
||||
char neg {'-'};
|
||||
|
||||
|
@ -48,19 +48,21 @@ extern "C"
|
||||
/** @addtogroup GncInt128
|
||||
* @ingroup QOF
|
||||
* @{
|
||||
* @brief provides a 128-bit int as a base class for GncNumeric.
|
||||
* @brief provides a 125-bit int as a base class for GncNumeric.
|
||||
*
|
||||
* All the usual operators are provided. Only the explicit integer
|
||||
* conversions throw; all other errors are indicated by the overflow
|
||||
* and NaN ("Not a Number") flags. Note that performing any operation
|
||||
* on an overflowed or NaN Gncint128 will yield an overflowed or NaN
|
||||
* result, so calling routines need not check until the end of a
|
||||
* chained calculation.
|
||||
* In order to make space for the status flags the upper leg is limited to
|
||||
* 0x1fffffffffffffff. Attempting to construct a GncInt128 with a larger upper
|
||||
* leg will throw a std::overflow_error.
|
||||
*
|
||||
* All the usual operators are provided. Only the constructors and explicit
|
||||
* integer conversions throw; all other errors are indicated by the overflow and
|
||||
* NaN ("Not a Number") flags. Note that performing any operation on an
|
||||
* overflowed or NaN Gncint128 will yield an overflowed or NaN result, so
|
||||
* calling routines need not check until the end of a chained calculation.
|
||||
* GncInt128 uses implicit copy and move constructors and implicit destructor.
|
||||
*/
|
||||
class GncInt128
|
||||
{
|
||||
unsigned char m_flags;
|
||||
uint64_t m_hi;
|
||||
uint64_t m_lo;
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "../gnc-int128.hpp"
|
||||
|
||||
static constexpr uint64_t UPPER_MAX{2305843009213693951};
|
||||
|
||||
TEST(qofint128_constructors, test_default_constructor)
|
||||
{
|
||||
GncInt128 value {};
|
||||
@ -36,112 +38,146 @@ TEST(qofint128_constructors, test_default_constructor)
|
||||
|
||||
TEST(qofint128_constructors, test_single_arg_constructor)
|
||||
{
|
||||
GncInt128 value1 (INT64_C(0));
|
||||
EXPECT_TRUE (value1.isZero());
|
||||
EXPECT_FALSE (value1.isNeg());
|
||||
EXPECT_FALSE (value1.isBig());
|
||||
EXPECT_FALSE (value1.isOverflow());
|
||||
EXPECT_FALSE (value1.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value1 (INT64_C(0));
|
||||
EXPECT_TRUE (value1.isZero());
|
||||
EXPECT_FALSE (value1.isNeg());
|
||||
EXPECT_FALSE (value1.isBig());
|
||||
EXPECT_FALSE (value1.isOverflow());
|
||||
EXPECT_FALSE (value1.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value2 (INT64_C(567894392130486208));
|
||||
EXPECT_FALSE (value2.isZero());
|
||||
EXPECT_FALSE (value2.isNeg());
|
||||
EXPECT_FALSE (value2.isBig());
|
||||
EXPECT_FALSE (value2.isOverflow());
|
||||
EXPECT_FALSE (value2.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value2 (INT64_C(567894392130486208));
|
||||
EXPECT_FALSE (value2.isZero());
|
||||
EXPECT_FALSE (value2.isNeg());
|
||||
EXPECT_FALSE (value2.isBig());
|
||||
EXPECT_FALSE (value2.isOverflow());
|
||||
EXPECT_FALSE (value2.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value3 (INT64_C(-567894392130486208));
|
||||
EXPECT_FALSE (value3.isZero());
|
||||
EXPECT_TRUE (value3.isNeg());
|
||||
EXPECT_FALSE (value3.isBig());
|
||||
EXPECT_FALSE (value3.isOverflow());
|
||||
EXPECT_FALSE (value3.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value3 (INT64_C(-567894392130486208));
|
||||
EXPECT_FALSE (value3.isZero());
|
||||
EXPECT_TRUE (value3.isNeg());
|
||||
EXPECT_FALSE (value3.isBig());
|
||||
EXPECT_FALSE (value3.isOverflow());
|
||||
EXPECT_FALSE (value3.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value4 (UINT64_C(13567894392130486208));
|
||||
EXPECT_FALSE (value4.isZero());
|
||||
EXPECT_FALSE (value4.isNeg());
|
||||
EXPECT_TRUE (value4.isBig());
|
||||
EXPECT_FALSE (value4.isOverflow());
|
||||
EXPECT_FALSE (value4.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value4 (UINT64_C(13567894392130486208));
|
||||
EXPECT_FALSE (value4.isZero());
|
||||
EXPECT_FALSE (value4.isNeg());
|
||||
EXPECT_TRUE (value4.isBig());
|
||||
EXPECT_FALSE (value4.isOverflow());
|
||||
EXPECT_FALSE (value4.isNan());
|
||||
});
|
||||
}
|
||||
|
||||
TEST(qofint128_constructors, test_double_arg_constructor)
|
||||
{
|
||||
GncInt128 value1 (INT64_C(0), INT64_C(0));
|
||||
EXPECT_TRUE (value1.isZero());
|
||||
EXPECT_FALSE (value1.isNeg());
|
||||
EXPECT_FALSE (value1.isBig());
|
||||
EXPECT_FALSE (value1.isOverflow());
|
||||
EXPECT_FALSE (value1.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value1 (INT64_C(0), INT64_C(0));
|
||||
EXPECT_TRUE (value1.isZero());
|
||||
EXPECT_FALSE (value1.isNeg());
|
||||
EXPECT_FALSE (value1.isBig());
|
||||
EXPECT_FALSE (value1.isOverflow());
|
||||
EXPECT_FALSE (value1.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value2 (INT64_C(0), INT64_C(567894392130486208));
|
||||
EXPECT_FALSE (value2.isZero());
|
||||
EXPECT_FALSE (value2.isNeg());
|
||||
EXPECT_FALSE (value2.isBig());
|
||||
EXPECT_FALSE (value2.isOverflow());
|
||||
EXPECT_FALSE (value2.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value2 (INT64_C(0), INT64_C(567894392130486208));
|
||||
EXPECT_FALSE (value2.isZero());
|
||||
EXPECT_FALSE (value2.isNeg());
|
||||
EXPECT_FALSE (value2.isBig());
|
||||
EXPECT_FALSE (value2.isOverflow());
|
||||
EXPECT_FALSE (value2.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value3 (INT64_C(567894392130486208), INT64_C(0));
|
||||
EXPECT_FALSE (value3.isZero());
|
||||
EXPECT_FALSE (value3.isNeg());
|
||||
EXPECT_TRUE (value3.isBig());
|
||||
EXPECT_FALSE (value3.isOverflow());
|
||||
EXPECT_FALSE (value3.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value3 (INT64_C(567894392130486208), INT64_C(0));
|
||||
EXPECT_FALSE (value3.isZero());
|
||||
EXPECT_FALSE (value3.isNeg());
|
||||
EXPECT_TRUE (value3.isBig());
|
||||
EXPECT_FALSE (value3.isOverflow());
|
||||
EXPECT_FALSE (value3.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value4 (INT64_C(567894392130486208), INT64_C(567894392130486208));
|
||||
EXPECT_FALSE (value4.isZero());
|
||||
EXPECT_FALSE (value4.isNeg());
|
||||
EXPECT_TRUE (value4.isBig());
|
||||
EXPECT_FALSE (value4.isOverflow());
|
||||
EXPECT_FALSE (value4.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value4 (INT64_C(567894392130486208),
|
||||
INT64_C(567894392130486208));
|
||||
EXPECT_FALSE (value4.isZero());
|
||||
EXPECT_FALSE (value4.isNeg());
|
||||
EXPECT_TRUE (value4.isBig());
|
||||
EXPECT_FALSE (value4.isOverflow());
|
||||
EXPECT_FALSE (value4.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value5 (INT64_C(567894392130486208),
|
||||
INT64_C(-567894392130486208));
|
||||
EXPECT_FALSE (value5.isZero());
|
||||
EXPECT_FALSE (value5.isNeg());
|
||||
EXPECT_TRUE (value5.isBig());
|
||||
EXPECT_FALSE (value5.isOverflow());
|
||||
EXPECT_FALSE (value5.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value5 (INT64_C(567894392130486208),
|
||||
INT64_C(-567894392130486208));
|
||||
EXPECT_FALSE (value5.isZero());
|
||||
EXPECT_FALSE (value5.isNeg());
|
||||
EXPECT_TRUE (value5.isBig());
|
||||
EXPECT_FALSE (value5.isOverflow());
|
||||
EXPECT_FALSE (value5.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value6 (INT64_C(-567894392130486208),
|
||||
INT64_C(567894392130486208));
|
||||
EXPECT_FALSE (value6.isZero());
|
||||
EXPECT_TRUE (value6.isNeg());
|
||||
EXPECT_TRUE (value6.isBig());
|
||||
EXPECT_FALSE (value6.isOverflow());
|
||||
EXPECT_FALSE (value6.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value6 (INT64_C(-567894392130486208),
|
||||
INT64_C(567894392130486208));
|
||||
EXPECT_FALSE (value6.isZero());
|
||||
EXPECT_TRUE (value6.isNeg());
|
||||
EXPECT_TRUE (value6.isBig());
|
||||
EXPECT_FALSE (value6.isOverflow());
|
||||
EXPECT_FALSE (value6.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value7 (UINT64_C(13567894392130486208),
|
||||
UINT64_C(13567894392130486208), GncInt128::pos);
|
||||
EXPECT_FALSE (value7.isZero());
|
||||
EXPECT_FALSE (value7.isNeg());
|
||||
EXPECT_TRUE (value7.isBig());
|
||||
EXPECT_FALSE (value7.isOverflow());
|
||||
EXPECT_FALSE (value7.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value7 (UINT64_C(1695986799016310843),
|
||||
UINT64_C(13567894392130486208), GncInt128::pos);
|
||||
EXPECT_FALSE (value7.isZero());
|
||||
EXPECT_FALSE (value7.isNeg());
|
||||
EXPECT_TRUE (value7.isBig());
|
||||
EXPECT_FALSE (value7.isOverflow());
|
||||
EXPECT_FALSE (value7.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value8 (UINT64_C(13567894392130486208),
|
||||
UINT64_C(13567894392130486208), GncInt128::neg);
|
||||
EXPECT_FALSE (value8.isZero());
|
||||
EXPECT_TRUE (value8.isNeg());
|
||||
EXPECT_TRUE (value8.isBig());
|
||||
EXPECT_FALSE (value8.isOverflow());
|
||||
EXPECT_FALSE (value8.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value8 (UINT64_C(1695986799016310843),
|
||||
UINT64_C(13567894392130486208), GncInt128::neg);
|
||||
EXPECT_FALSE (value8.isZero());
|
||||
EXPECT_TRUE (value8.isNeg());
|
||||
EXPECT_TRUE (value8.isBig());
|
||||
EXPECT_FALSE (value8.isOverflow());
|
||||
EXPECT_FALSE (value8.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value9 (UINT64_C(13567894392130486208),
|
||||
UINT64_C(13567894392130486208), GncInt128::overflow);
|
||||
EXPECT_FALSE (value9.isZero());
|
||||
EXPECT_FALSE (value9.isNeg());
|
||||
EXPECT_TRUE (value9.isBig());
|
||||
EXPECT_TRUE (value9.isOverflow());
|
||||
EXPECT_FALSE (value9.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value9 (UINT64_C(1695986799016310843),
|
||||
UINT64_C(13567894392130486208),
|
||||
GncInt128::overflow);
|
||||
EXPECT_FALSE (value9.isZero());
|
||||
EXPECT_FALSE (value9.isNeg());
|
||||
EXPECT_TRUE (value9.isBig());
|
||||
EXPECT_TRUE (value9.isOverflow());
|
||||
EXPECT_FALSE (value9.isNan());
|
||||
});
|
||||
|
||||
GncInt128 value10 (UINT64_C(13567894392130486208),
|
||||
UINT64_C(13567894392130486208), GncInt128::NaN);
|
||||
EXPECT_FALSE (value10.isZero());
|
||||
EXPECT_FALSE (value10.isNeg());
|
||||
EXPECT_TRUE (value10.isBig());
|
||||
EXPECT_FALSE (value10.isOverflow());
|
||||
EXPECT_TRUE (value10.isNan());
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value10 (UINT64_C(1695986799016310843),
|
||||
UINT64_C(13567894392130486208), GncInt128::NaN);
|
||||
EXPECT_FALSE (value10.isZero());
|
||||
EXPECT_FALSE (value10.isNeg());
|
||||
EXPECT_TRUE (value10.isBig());
|
||||
EXPECT_FALSE (value10.isOverflow());
|
||||
EXPECT_TRUE (value10.isNan());
|
||||
});
|
||||
|
||||
EXPECT_THROW(GncInt128 value10 (UINT64_C(13567894392130486208),
|
||||
UINT64_C(13567894392130486208)),
|
||||
std::overflow_error);
|
||||
}
|
||||
|
||||
TEST(qofint128_functions, test_int_functions)
|
||||
@ -149,9 +185,13 @@ TEST(qofint128_functions, test_int_functions)
|
||||
int64_t arg {INT64_C(567894392130486208)};
|
||||
int64_t narg {INT64_C(-567894392130486208)};
|
||||
uint64_t uarg {UINT64_C(13567894392130486208)};
|
||||
GncInt128 value1 (INT64_C(0), arg);
|
||||
EXPECT_EQ (arg, static_cast<int64_t>(value1));
|
||||
EXPECT_EQ (static_cast<uint64_t>(arg), static_cast<uint64_t>(value1));
|
||||
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 value1 (INT64_C(0), arg);
|
||||
EXPECT_EQ (arg, static_cast<int64_t>(value1));
|
||||
EXPECT_EQ (static_cast<uint64_t>(arg),
|
||||
static_cast<uint64_t>(value1));
|
||||
});
|
||||
|
||||
GncInt128 value2 (UINT64_C(0), uarg);
|
||||
EXPECT_THROW (auto v = static_cast<int64_t>(value2), std::overflow_error);
|
||||
@ -291,19 +331,22 @@ TEST(qofint128_functions, add_and_subtract)
|
||||
{
|
||||
/* UINT64_MAX = 18,446,744,073,709,551,615
|
||||
* INT64_MAX = 9,223,372,036,854,775,807
|
||||
* barg + sarg = INT64_MAX
|
||||
* upper leg max = 2,305,843,009,213,693,951
|
||||
* barg + marg = INT64_MAX
|
||||
* barg + uarg = UINT64_MAX
|
||||
* marg + sarg = upper leg max
|
||||
*/
|
||||
int64_t barg {INT64_C(4878849681579065407)};
|
||||
int64_t sarg {INT64_C(4344522355275710400)};
|
||||
int64_t marg {INT64_C(4344522355275710400)};
|
||||
int64_t sarg {INT64_C(267163663151677502)};
|
||||
uint64_t uarg {UINT64_C(13567894392130486208)};
|
||||
|
||||
GncInt128 smallest (sarg + 100);
|
||||
GncInt128 smallest (marg + 100);
|
||||
GncInt128 smaller (barg + 500);
|
||||
GncInt128 small (uarg);
|
||||
GncInt128 big (sarg, barg);
|
||||
GncInt128 bigger (static_cast<uint64_t>(barg), uarg);
|
||||
GncInt128 biggest (uarg, static_cast<uint64_t>(barg));
|
||||
GncInt128 bigger (marg, barg);
|
||||
GncInt128 biggest (sarg, static_cast<uint64_t>(barg) + uarg);
|
||||
GncInt128 nsmall (UINT64_C(0), uarg, GncInt128::neg);
|
||||
|
||||
EXPECT_EQ (GncInt128(INT64_C(2), INT64_C(499)), small += smaller);
|
||||
@ -311,12 +354,11 @@ TEST(qofint128_functions, add_and_subtract)
|
||||
nsmall -= smaller);
|
||||
|
||||
EXPECT_EQ (GncInt128(uarg), small -= smaller);
|
||||
EXPECT_EQ (GncInt128(static_cast<uint64_t>(barg + sarg/2), UINT64_MAX),
|
||||
EXPECT_EQ (GncInt128(UINT64_C(2305843009213693951),
|
||||
UINT64_C(9757699363158130814)),
|
||||
bigger += big);
|
||||
EXPECT_EQ (GncInt128(static_cast<uint64_t>(barg), uarg), bigger -= big);
|
||||
EXPECT_EQ (GncInt128(marg, barg), bigger -= big);
|
||||
bigger += biggest;
|
||||
EXPECT_EQ (GncInt128(UINT64_MAX, UINT64_MAX), bigger);
|
||||
bigger += smallest;
|
||||
EXPECT_TRUE (bigger.isOverflow());
|
||||
bigger -= biggest;
|
||||
EXPECT_TRUE (bigger.isOverflow());
|
||||
@ -325,38 +367,70 @@ TEST(qofint128_functions, add_and_subtract)
|
||||
TEST(qofint128_functions, multiply)
|
||||
{
|
||||
int64_t barg {INT64_C(4878849681579065407)};
|
||||
int64_t sarg {INT64_C(4344522355275710400)};
|
||||
int64_t marg {INT64_C(4344522355275710400)};
|
||||
int64_t sarg {INT64_C(267163663151677502)};
|
||||
uint64_t uarg {UINT64_C(13567894392130486208)};
|
||||
|
||||
GncInt128 smallest (sarg);
|
||||
GncInt128 smallest (marg);
|
||||
GncInt128 smaller (barg);
|
||||
GncInt128 small (uarg);
|
||||
GncInt128 big (sarg, barg);
|
||||
GncInt128 bigger (static_cast<uint64_t>(barg), uarg);
|
||||
GncInt128 bigger (sarg, uarg);
|
||||
GncInt128 nsmaller (-barg);
|
||||
GncInt128 nsmallest (-marg);
|
||||
GncInt128 tiny (53);
|
||||
GncInt128 teensy (37);
|
||||
|
||||
small *= big;
|
||||
EXPECT_TRUE (small.isOverflow());
|
||||
big *= bigger;
|
||||
EXPECT_TRUE (big.isOverflow());
|
||||
EXPECT_EQ (GncInt128(UINT64_C(1149052180967758316), UINT64_C(6323251814974894144)), smallest *= smaller);
|
||||
EXPECT_FALSE (smallest.isOverflow());
|
||||
EXPECT_NO_THROW({
|
||||
small *= big;
|
||||
EXPECT_TRUE (small.isOverflow());
|
||||
big *= bigger;
|
||||
EXPECT_TRUE (big.isOverflow());
|
||||
EXPECT_EQ(1961, tiny * teensy);
|
||||
EXPECT_EQ(-1961, -tiny * teensy);
|
||||
EXPECT_EQ(-1961, tiny * -teensy);
|
||||
EXPECT_EQ(1961, -tiny * -teensy);
|
||||
EXPECT_EQ (GncInt128(INT64_C(1149052180967758316),
|
||||
UINT64_C(6323251814974894144)),
|
||||
smallest * smaller);
|
||||
EXPECT_EQ (GncInt128(INT64_C(-1149052180967758316),
|
||||
UINT64_C(6323251814974894144)),
|
||||
-smallest * smaller);
|
||||
EXPECT_EQ (GncInt128(INT64_C(-1149052180967758316),
|
||||
UINT64_C(6323251814974894144)),
|
||||
smallest * -smaller);
|
||||
EXPECT_EQ (GncInt128(INT64_C(1149052180967758316),
|
||||
UINT64_C(6323251814974894144)),
|
||||
-smallest * -smaller);
|
||||
EXPECT_EQ (GncInt128(INT64_C(-1149052180967758316),
|
||||
UINT64_C(6323251814974894144)),
|
||||
nsmallest * smaller);
|
||||
EXPECT_EQ (GncInt128(INT64_C(-1149052180967758316),
|
||||
UINT64_C(6323251814974894144)),
|
||||
smallest * nsmaller);
|
||||
EXPECT_EQ (GncInt128(INT64_C(1149052180967758316),
|
||||
UINT64_C(6323251814974894144)),
|
||||
nsmallest * nsmaller);
|
||||
EXPECT_FALSE (smallest.isOverflow());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
TEST(qofint128_functions, divide)
|
||||
{
|
||||
int64_t barg {INT64_C(4878849681579065407)};
|
||||
int64_t sarg {INT64_C(4344522355275710400)};
|
||||
int64_t marg {INT64_C(4344522355275710400)};
|
||||
int64_t sarg {INT64_C(267163663151677502)};
|
||||
uint64_t uarg {UINT64_C(13567894392130486208)};
|
||||
|
||||
GncInt128 zero (INT64_C(0));
|
||||
GncInt128 one (INT64_C(1));
|
||||
GncInt128 two (INT64_C(2));
|
||||
GncInt128 smallest (sarg);
|
||||
GncInt128 smallest (marg);
|
||||
GncInt128 smaller (barg);
|
||||
GncInt128 small (uarg);
|
||||
GncInt128 big (sarg, barg);
|
||||
GncInt128 bigger (static_cast<uint64_t>(barg), uarg);
|
||||
GncInt128 bigger (static_cast<uint64_t>(sarg), uarg);
|
||||
GncInt128 nsmall = -small;
|
||||
GncInt128 nbig = -bigger;
|
||||
|
||||
@ -392,28 +466,24 @@ TEST(qofint128_functions, divide)
|
||||
EXPECT_EQ (zero, r);
|
||||
|
||||
big.div (smaller, q, r);
|
||||
EXPECT_EQ (GncInt128(INT64_C(8213236443097627766)), q);
|
||||
EXPECT_EQ (GncInt128(INT64_C(3162679692459777845)), r);
|
||||
EXPECT_EQ (GncInt128(INT64_C(505067796878574019)), q);
|
||||
EXPECT_EQ (GncInt128(INT64_C(1659575984014676290)), r);
|
||||
|
||||
bigger.div (big, q, r);
|
||||
EXPECT_EQ (two, q);
|
||||
EXPECT_EQ (GncInt128(UINT64_C(534327326303355007),
|
||||
UINT64_C(3810195028972355394)), r);
|
||||
EXPECT_EQ (GncInt128(UINT64_C(3810195028972355394)), r);
|
||||
|
||||
bigger.div (-big, q, r);
|
||||
EXPECT_EQ (-two, q);
|
||||
EXPECT_EQ (GncInt128(UINT64_C(534327326303355007),
|
||||
UINT64_C(3810195028972355394)), r);
|
||||
EXPECT_EQ (GncInt128(UINT64_C(3810195028972355394)), r);
|
||||
|
||||
nbig.div (-big, q, r);
|
||||
EXPECT_EQ (two, q);
|
||||
EXPECT_EQ (GncInt128(UINT64_C(534327326303355007),
|
||||
UINT64_C(3810195028972355394)), r);
|
||||
EXPECT_EQ (GncInt128(UINT64_C(3810195028972355394)), r);
|
||||
|
||||
nbig.div (-big, q, r);
|
||||
EXPECT_EQ (two, q);
|
||||
EXPECT_EQ (GncInt128(UINT64_C(534327326303355007),
|
||||
UINT64_C(3810195028972355394)), r);
|
||||
EXPECT_EQ (GncInt128(UINT64_C(3810195028972355394)), r);
|
||||
|
||||
big.div (bigger, q, r);
|
||||
EXPECT_EQ (zero, q);
|
||||
@ -422,7 +492,7 @@ TEST(qofint128_functions, divide)
|
||||
big.div (big - 1, q, r);
|
||||
EXPECT_EQ(one, q);
|
||||
EXPECT_EQ(one, r);
|
||||
|
||||
|
||||
EXPECT_EQ (big, big %= bigger);
|
||||
EXPECT_EQ (two, bigger /= big);
|
||||
}
|
||||
@ -430,24 +500,27 @@ TEST(qofint128_functions, divide)
|
||||
TEST(qofint128_functions, GCD)
|
||||
{
|
||||
int64_t barg {INT64_C(4878849681579065407)};
|
||||
int64_t sarg {INT64_C(4344522355275710401)};
|
||||
int64_t marg {INT64_C(4344522355275710400)};
|
||||
int64_t sarg {INT64_C(267163663151677502)};
|
||||
uint64_t uarg {UINT64_C(13567894392130486208)};
|
||||
|
||||
GncInt128 one (INT64_C(1));
|
||||
GncInt128 smallest (sarg);
|
||||
GncInt128 smaller (barg);
|
||||
GncInt128 small (uarg);
|
||||
GncInt128 smaller (marg);
|
||||
GncInt128 small (barg);
|
||||
|
||||
GncInt128 big = smaller * smallest;
|
||||
GncInt128 bigger = small * smaller;
|
||||
EXPECT_NO_THROW({
|
||||
GncInt128 big = smaller * smallest;
|
||||
GncInt128 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));
|
||||
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 (2, bigger.gcd (smallest));
|
||||
EXPECT_EQ (big >> 1, smaller.lcm (smallest));
|
||||
});
|
||||
}
|
||||
|
||||
TEST(qofint128_functions, pow)
|
||||
|
Loading…
Reference in New Issue
Block a user