mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Convert GncRational to throw instead of using a status byte.
More consistent with GncNumeric and saves a word of memory per instance. Still bleeping huge because the two GncInt128s each need 128 bits (2 or 4 words) plus a word for status (for 3 bits!). Also provide a couple of convenience functions, is_big() and valid() to test if the either numerator and denominator is big or overflowed or NaN.
This commit is contained in:
parent
ff7e6a37d5
commit
c633e80a24
@ -211,6 +211,12 @@ GncInt128::isNan () const noexcept
|
|||||||
return (m_flags & NaN);
|
return (m_flags & NaN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
GncInt128::valid() const noexcept
|
||||||
|
{
|
||||||
|
return !(m_flags & (overflow | NaN));
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GncInt128::isZero() const noexcept
|
GncInt128::isZero() const noexcept
|
||||||
{
|
{
|
||||||
|
@ -210,6 +210,10 @@ enum // Values for m_flags
|
|||||||
* @return true if the object represents 0.
|
* @return true if the object represents 0.
|
||||||
*/
|
*/
|
||||||
bool isZero() const noexcept;
|
bool isZero() const noexcept;
|
||||||
|
/**
|
||||||
|
* @return true if neither the overflow nor nan flags are set.
|
||||||
|
*/
|
||||||
|
bool valid() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the number of bits used to represent the value
|
* @return the number of bits used to represent the value
|
||||||
|
@ -328,14 +328,7 @@ GncNumeric::to_decimal(unsigned int max_places) const
|
|||||||
return GncNumeric(m_num / excess, powten(max_places));
|
return GncNumeric(m_num / excess, powten(max_places));
|
||||||
}
|
}
|
||||||
GncRational rr(*this);
|
GncRational rr(*this);
|
||||||
rr.round(powten(max_places), RoundType::never);
|
rr.round(powten(max_places), RoundType::never); //May throw
|
||||||
if (rr.m_error)
|
|
||||||
{
|
|
||||||
std::ostringstream msg;
|
|
||||||
msg << "GncNumeric " << *this
|
|
||||||
<< " could not be represented as a decimal without rounding.\n";
|
|
||||||
throw std::range_error(msg.str());
|
|
||||||
}
|
|
||||||
/* rr might have gotten reduced a bit too much; if so, put it back: */
|
/* rr might have gotten reduced a bit too much; if so, put it back: */
|
||||||
unsigned int pwr{1};
|
unsigned int pwr{1};
|
||||||
for (; pwr <= max_places && !(rr.m_den % powten(pwr)); ++pwr);
|
for (; pwr <= max_places && !(rr.m_den % powten(pwr)); ++pwr);
|
||||||
@ -804,11 +797,8 @@ gnc_numeric_add(gnc_numeric a, gnc_numeric b,
|
|||||||
GncRational ar(a), br(b);
|
GncRational ar(a), br(b);
|
||||||
auto sum = ar + br;
|
auto sum = ar + br;
|
||||||
sum.round(denom, static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK));
|
sum.round(denom, static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK));
|
||||||
if (sum.m_error)
|
|
||||||
return gnc_numeric_error(sum.m_error);
|
if (sum.is_big() || !sum.valid())
|
||||||
if (sum.m_num.isBig() || sum.m_den.isBig() ||
|
|
||||||
sum.m_num.isOverflow() || sum.m_den.isOverflow() ||
|
|
||||||
sum.m_num.isNan() || sum.m_den.isNan())
|
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
return GncNumeric(sum);
|
return GncNumeric(sum);
|
||||||
}
|
}
|
||||||
@ -827,6 +817,11 @@ gnc_numeric_add(gnc_numeric a, gnc_numeric b,
|
|||||||
PWARN("%s", err.what());
|
PWARN("%s", err.what());
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
catch (const std::domain_error& err)
|
||||||
|
{
|
||||||
|
PWARN("%s", err.what());
|
||||||
|
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************
|
/* *******************************************************************
|
||||||
@ -854,11 +849,7 @@ gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
|
|||||||
GncRational ar(a), br(b);
|
GncRational ar(a), br(b);
|
||||||
auto sum = ar - br;
|
auto sum = ar - br;
|
||||||
sum.round(denom, static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK));
|
sum.round(denom, static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK));
|
||||||
if (sum.m_error)
|
if (sum.is_big() || !sum.valid())
|
||||||
return gnc_numeric_error(sum.m_error);
|
|
||||||
if (sum.m_num.isBig() || sum.m_den.isBig() ||
|
|
||||||
sum.m_num.isOverflow() || sum.m_den.isOverflow() ||
|
|
||||||
sum.m_num.isNan() || sum.m_den.isNan())
|
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
return GncNumeric(sum);
|
return GncNumeric(sum);
|
||||||
}
|
}
|
||||||
@ -877,6 +868,11 @@ gnc_numeric_sub(gnc_numeric a, gnc_numeric b,
|
|||||||
PWARN("%s", err.what());
|
PWARN("%s", err.what());
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
catch (const std::domain_error& err)
|
||||||
|
{
|
||||||
|
PWARN("%s", err.what());
|
||||||
|
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************
|
/* *******************************************************************
|
||||||
@ -903,11 +899,7 @@ gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
|
|||||||
GncRational ar(a), br(b);
|
GncRational ar(a), br(b);
|
||||||
auto prod = ar * br;
|
auto prod = ar * br;
|
||||||
prod.round(denom, static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK));
|
prod.round(denom, static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK));
|
||||||
if (prod.m_error)
|
if (prod.is_big() || !prod.valid())
|
||||||
return gnc_numeric_error(prod.m_error);
|
|
||||||
if (prod.m_num.isBig() || prod.m_den.isBig() ||
|
|
||||||
prod.m_num.isOverflow() || prod.m_den.isOverflow() ||
|
|
||||||
prod.m_num.isNan() || prod.m_den.isNan())
|
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
return GncNumeric(prod);
|
return GncNumeric(prod);
|
||||||
}
|
}
|
||||||
@ -926,6 +918,11 @@ gnc_numeric_mul(gnc_numeric a, gnc_numeric b,
|
|||||||
PWARN("%s", err.what());
|
PWARN("%s", err.what());
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
catch (const std::domain_error& err)
|
||||||
|
{
|
||||||
|
PWARN("%s", err.what());
|
||||||
|
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -953,11 +950,7 @@ gnc_numeric_div(gnc_numeric a, gnc_numeric b,
|
|||||||
GncRational ar(a), br(b);
|
GncRational ar(a), br(b);
|
||||||
auto quot = ar / br;
|
auto quot = ar / br;
|
||||||
quot.round(denom, static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK));
|
quot.round(denom, static_cast<RoundType>(how & GNC_NUMERIC_RND_MASK));
|
||||||
if (quot.m_error)
|
if (quot.is_big() || !quot.valid())
|
||||||
return gnc_numeric_error(quot.m_error);
|
|
||||||
if (quot.m_num.isBig() || quot.m_den.isBig() ||
|
|
||||||
quot.m_num.isOverflow() || quot.m_den.isOverflow() ||
|
|
||||||
quot.m_num.isNan() || quot.m_den.isNan())
|
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
return GncNumeric(quot);
|
return GncNumeric(quot);
|
||||||
}
|
}
|
||||||
@ -976,6 +969,11 @@ gnc_numeric_div(gnc_numeric a, gnc_numeric b,
|
|||||||
PWARN("%s", err.what());
|
PWARN("%s", err.what());
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
catch (const std::domain_error& err)
|
||||||
|
{
|
||||||
|
PWARN("%s", err.what());
|
||||||
|
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************
|
/* *******************************************************************
|
||||||
@ -1056,7 +1054,11 @@ gnc_numeric_reduce(gnc_numeric in)
|
|||||||
PWARN("%s", err.what());
|
PWARN("%s", err.what());
|
||||||
return gnc_numeric_error(GNC_ERROR_ARG);
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
||||||
}
|
}
|
||||||
|
catch (const std::domain_error& err)
|
||||||
|
{
|
||||||
|
PWARN("%s", err.what());
|
||||||
|
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1112,6 +1114,11 @@ gnc_numeric_invert(gnc_numeric num)
|
|||||||
PWARN("%s", err.what());
|
PWARN("%s", err.what());
|
||||||
return gnc_numeric_error(GNC_ERROR_ARG);
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
||||||
}
|
}
|
||||||
|
catch (const std::domain_error& err)
|
||||||
|
{
|
||||||
|
PWARN("%s", err.what());
|
||||||
|
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************
|
/* *******************************************************************
|
||||||
@ -1144,6 +1151,11 @@ double_to_gnc_numeric(double in, gint64 denom, gint how)
|
|||||||
PWARN("%s", err.what());
|
PWARN("%s", err.what());
|
||||||
return gnc_numeric_error(GNC_ERROR_ARG);
|
return gnc_numeric_error(GNC_ERROR_ARG);
|
||||||
}
|
}
|
||||||
|
catch (const std::domain_error& err)
|
||||||
|
{
|
||||||
|
PWARN("%s", err.what());
|
||||||
|
return gnc_numeric_error(GNC_ERROR_REMAINDER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *******************************************************************
|
/* *******************************************************************
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
|
|
||||||
GncRational::GncRational(GncNumeric n) noexcept :
|
GncRational::GncRational(GncNumeric n) noexcept :
|
||||||
m_num(n.num()), m_den(n.denom()), m_error(GNC_ERROR_OK)
|
m_num(n.num()), m_den(n.denom())
|
||||||
{
|
{
|
||||||
if (m_den.isNeg())
|
if (m_den.isNeg())
|
||||||
{
|
{
|
||||||
@ -36,7 +36,7 @@ GncRational::GncRational(GncNumeric n) noexcept :
|
|||||||
}
|
}
|
||||||
|
|
||||||
GncRational::GncRational (gnc_numeric n) noexcept :
|
GncRational::GncRational (gnc_numeric n) noexcept :
|
||||||
m_num (n.num), m_den (n.denom), m_error {GNC_ERROR_OK}
|
m_num (n.num), m_den (n.denom)
|
||||||
{
|
{
|
||||||
if (m_den.isNeg())
|
if (m_den.isNeg())
|
||||||
{
|
{
|
||||||
@ -45,13 +45,26 @@ GncRational::GncRational (gnc_numeric n) noexcept :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
GncRational::valid() const noexcept
|
||||||
|
{
|
||||||
|
if (m_num.valid() && m_den.valid())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
GncRational::is_big() const noexcept
|
||||||
|
{
|
||||||
|
if (m_num.isBig() || m_den.isBig())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
GncRational::operator gnc_numeric () const noexcept
|
GncRational::operator gnc_numeric () const noexcept
|
||||||
{
|
{
|
||||||
if (m_num.isOverflow() || m_num.isNan() ||
|
if (!valid())
|
||||||
m_den.isOverflow() || m_den.isNan())
|
|
||||||
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
return gnc_numeric_error(GNC_ERROR_OVERFLOW);
|
||||||
if (m_error != GNC_ERROR_OK)
|
|
||||||
return gnc_numeric_error (m_error);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return {static_cast<int64_t>(m_num), static_cast<int64_t>(m_den)};
|
return {static_cast<int64_t>(m_num), static_cast<int64_t>(m_den)};
|
||||||
@ -87,16 +100,12 @@ GncRational::inv () noexcept
|
|||||||
GncRational
|
GncRational
|
||||||
operator+(GncRational a, GncRational b)
|
operator+(GncRational a, GncRational b)
|
||||||
{
|
{
|
||||||
if (a.m_error || b.m_error)
|
if (!(a.valid() && b.valid()))
|
||||||
{
|
throw std::range_error("Operator+ called with out-of-range operand.");
|
||||||
if (b.m_error)
|
|
||||||
return GncRational(0, 1, b.m_error);
|
|
||||||
return GncRational(0, 1, a.m_error);
|
|
||||||
}
|
|
||||||
GncInt128 lcm = a.m_den.lcm(b.m_den);
|
GncInt128 lcm = a.m_den.lcm(b.m_den);
|
||||||
GncInt128 num(a.m_num * lcm / a.m_den + b.m_num * lcm / b.m_den);
|
GncInt128 num(a.m_num * lcm / a.m_den + b.m_num * lcm / b.m_den);
|
||||||
if (lcm.isOverflow() || lcm.isNan() || num.isOverflow() || num.isNan())
|
if (!(lcm.valid() && num.valid()))
|
||||||
return GncRational(0, 1, GNC_ERROR_OVERFLOW);
|
throw std::overflow_error("Operator+ overflowed.");
|
||||||
GncRational retval(num, lcm);
|
GncRational retval(num, lcm);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -111,15 +120,11 @@ operator-(GncRational a, GncRational b)
|
|||||||
GncRational
|
GncRational
|
||||||
operator*(GncRational a, GncRational b)
|
operator*(GncRational a, GncRational b)
|
||||||
{
|
{
|
||||||
if (a.m_error || b.m_error)
|
if (!(a.valid() && b.valid()))
|
||||||
{
|
throw std::range_error("Operator* called with out-of-range operand.");
|
||||||
if (b.m_error)
|
|
||||||
return GncRational(0, 1, b.m_error);
|
|
||||||
return GncRational(0, 1, a.m_error);
|
|
||||||
}
|
|
||||||
GncInt128 num (a.m_num * b.m_num), den(a.m_den * b.m_den);
|
GncInt128 num (a.m_num * b.m_num), den(a.m_den * b.m_den);
|
||||||
if (num.isOverflow() || num.isNan() || den.isOverflow() || den.isNan())
|
if (!(num.valid() && den.valid()))
|
||||||
return GncRational(0, 1, GNC_ERROR_OVERFLOW);
|
throw std::overflow_error("Operator* overflowed.");
|
||||||
GncRational retval(num, den);
|
GncRational retval(num, den);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -127,12 +132,10 @@ operator*(GncRational a, GncRational b)
|
|||||||
GncRational
|
GncRational
|
||||||
operator/(GncRational a, GncRational b)
|
operator/(GncRational a, GncRational b)
|
||||||
{
|
{
|
||||||
if (a.m_error || b.m_error)
|
if (!(a.valid() && b.valid()))
|
||||||
{
|
throw std::range_error("Operator/ called with out-of-range operand.");
|
||||||
if (b.m_error)
|
if (b.m_num == 0)
|
||||||
return GncRational(0, 1, b.m_error);
|
throw std::underflow_error("Divide by 0.");
|
||||||
return GncRational(0, 1, a.m_error);
|
|
||||||
}
|
|
||||||
if (b.m_num.isNeg())
|
if (b.m_num.isNeg())
|
||||||
{
|
{
|
||||||
a.m_num = -a.m_num;
|
a.m_num = -a.m_num;
|
||||||
@ -155,8 +158,8 @@ operator/(GncRational a, GncRational b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GncInt128 num(a.m_num * b.m_den), den(a.m_den * b.m_num);
|
GncInt128 num(a.m_num * b.m_den), den(a.m_den * b.m_num);
|
||||||
if (num.isOverflow() || num.isNan() || den.isOverflow() || den.isNan())
|
if (!(num.valid() && den.valid()))
|
||||||
return GncRational(0, 1, GNC_ERROR_OVERFLOW);
|
throw std::overflow_error("Operator/ overflowed.");
|
||||||
return GncRational(num, den);
|
return GncRational(num, den);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,8 +264,7 @@ GncRational::round (GncInt128 new_den, RoundType rtype)
|
|||||||
switch (rtype)
|
switch (rtype)
|
||||||
{
|
{
|
||||||
case RoundType::never:
|
case RoundType::never:
|
||||||
m_error = GNC_ERROR_REMAINDER;
|
throw std::domain_error("Rounding required when 'never round' specified.");
|
||||||
return;
|
|
||||||
case RoundType::floor:
|
case RoundType::floor:
|
||||||
if (new_num.isNeg()) ++new_num;
|
if (new_num.isNeg()) ++new_num;
|
||||||
break;
|
break;
|
||||||
|
@ -37,16 +37,23 @@ enum class DenomType;
|
|||||||
class GncRational
|
class GncRational
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GncRational() : m_num(0), m_den(1), m_error(GNC_ERROR_OK) {}
|
GncRational() : m_num(0), m_den(1) {}
|
||||||
GncRational (gnc_numeric n) noexcept;
|
GncRational (gnc_numeric n) noexcept;
|
||||||
GncRational(GncNumeric n) noexcept;
|
GncRational(GncNumeric n) noexcept;
|
||||||
GncRational (GncInt128 num, GncInt128 den,
|
GncRational (GncInt128 num, GncInt128 den) noexcept
|
||||||
GNCNumericErrorCode err=GNC_ERROR_OK) noexcept
|
: m_num(num), m_den(den) {}
|
||||||
: m_num(num), m_den(den), m_error(err) {}
|
|
||||||
GncRational(const GncRational& rhs) = default;
|
GncRational(const GncRational& rhs) = default;
|
||||||
GncRational(GncRational&& rhs) = default;
|
GncRational(GncRational&& rhs) = default;
|
||||||
GncRational& operator=(const GncRational& rhs) = default;
|
GncRational& operator=(const GncRational& rhs) = default;
|
||||||
GncRational& operator=(GncRational&& rhs) = default;
|
GncRational& operator=(GncRational&& rhs) = default;
|
||||||
|
/** Report if both members are valid numbers.
|
||||||
|
* \return true if neither numerator nor denominator are Nan or Overflowed.
|
||||||
|
*/
|
||||||
|
bool valid() const noexcept;
|
||||||
|
/** Report if either numerator or denominator are too big to fit in an int64_t.
|
||||||
|
* \return true if either is too big.
|
||||||
|
*/
|
||||||
|
bool is_big() const noexcept;
|
||||||
/** Conversion operator; use static_cast<gnc_numeric>(foo). */
|
/** Conversion operator; use static_cast<gnc_numeric>(foo). */
|
||||||
operator gnc_numeric() const noexcept;
|
operator gnc_numeric() const noexcept;
|
||||||
/** Make a new GncRational with the opposite sign. */
|
/** Make a new GncRational with the opposite sign. */
|
||||||
@ -78,7 +85,6 @@ public:
|
|||||||
|
|
||||||
GncInt128 m_num;
|
GncInt128 m_num;
|
||||||
GncInt128 m_den;
|
GncInt128 m_den;
|
||||||
GNCNumericErrorCode m_error;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GncRational operator+(GncRational a, GncRational b);
|
GncRational operator+(GncRational a, GncRational b);
|
||||||
|
@ -499,7 +499,7 @@ TEST(gnc_numeric_functions, test_conversion_to_decimal)
|
|||||||
EXPECT_EQ(1000, r.denom());
|
EXPECT_EQ(1000, r.denom());
|
||||||
EXPECT_THROW(r = a.to_decimal(2), std::range_error);
|
EXPECT_THROW(r = a.to_decimal(2), std::range_error);
|
||||||
GncNumeric b(123456789, 456);
|
GncNumeric b(123456789, 456);
|
||||||
EXPECT_THROW(r = b.to_decimal(), std::range_error);
|
EXPECT_THROW(r = b.to_decimal(), std::domain_error);
|
||||||
GncNumeric c(123456789, 450);
|
GncNumeric c(123456789, 450);
|
||||||
EXPECT_NO_THROW(r = c.to_decimal());
|
EXPECT_NO_THROW(r = c.to_decimal());
|
||||||
EXPECT_EQ(27434842, r.num());
|
EXPECT_EQ(27434842, r.num());
|
||||||
|
@ -28,118 +28,109 @@
|
|||||||
|
|
||||||
TEST(gncrational_constructors, test_default_constructor)
|
TEST(gncrational_constructors, test_default_constructor)
|
||||||
{
|
{
|
||||||
GncRational value;
|
EXPECT_NO_THROW({
|
||||||
EXPECT_EQ(value.m_num, 0);
|
GncRational value;
|
||||||
EXPECT_EQ(value.m_den, 1);
|
EXPECT_EQ(value.m_num, 0);
|
||||||
EXPECT_EQ(value.m_error, GNC_ERROR_OK);
|
EXPECT_EQ(value.m_den, 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(gncrational_constructors, test_gnc_numeric_constructor)
|
TEST(gncrational_constructors, test_gnc_numeric_constructor)
|
||||||
{
|
{
|
||||||
gnc_numeric input = gnc_numeric_create(123, 456);
|
gnc_numeric input = gnc_numeric_create(123, 456);
|
||||||
GncRational value(input);
|
EXPECT_NO_THROW({
|
||||||
EXPECT_EQ(input.num, value.m_num);
|
GncRational value(input);
|
||||||
EXPECT_EQ(input.denom, value.m_den);
|
EXPECT_EQ(input.num, value.m_num);
|
||||||
EXPECT_EQ(value.m_error, GNC_ERROR_OK);
|
EXPECT_EQ(input.denom, value.m_den);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(gncrational_constructors, test_gnc_int128_constructor)
|
TEST(gncrational_constructors, test_gnc_int128_constructor)
|
||||||
{
|
{
|
||||||
GncInt128 num(123), denom(456);
|
GncInt128 num(123), denom(456);
|
||||||
GncRational value(num, denom);
|
EXPECT_NO_THROW({
|
||||||
EXPECT_EQ(123, value.m_num);
|
GncRational value(num, denom);
|
||||||
EXPECT_EQ(456, value.m_den);
|
EXPECT_EQ(123, value.m_num);
|
||||||
EXPECT_EQ(GNC_ERROR_OK, value.m_error);
|
EXPECT_EQ(456, value.m_den);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(gncrational_constructors, test_implicit_int_constructor)
|
TEST(gncrational_constructors, test_implicit_int_constructor)
|
||||||
{
|
{
|
||||||
int num(123), denom(456);
|
int num(123), denom(456);
|
||||||
GncRational value(num, denom);
|
EXPECT_NO_THROW({
|
||||||
EXPECT_EQ(123, value.m_num);
|
GncRational value(num, denom);
|
||||||
EXPECT_EQ(456, value.m_den);
|
EXPECT_EQ(123, value.m_num);
|
||||||
EXPECT_EQ(GNC_ERROR_OK, value.m_error);
|
EXPECT_EQ(456, value.m_den);
|
||||||
}
|
});
|
||||||
|
|
||||||
TEST(gncrational_constructors, test_with_error_code)
|
|
||||||
{
|
|
||||||
int num(123), denom(456);
|
|
||||||
GncRational value(num, denom, GNC_ERROR_OVERFLOW);
|
|
||||||
EXPECT_EQ(123, value.m_num);
|
|
||||||
EXPECT_EQ(456, value.m_den);
|
|
||||||
EXPECT_EQ(GNC_ERROR_OVERFLOW, value.m_error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(gncrational_operators, test_addition)
|
TEST(gncrational_operators, test_addition)
|
||||||
{
|
{
|
||||||
GncRational a(123456789987654321, 1000000000);
|
EXPECT_NO_THROW({
|
||||||
GncRational b(65432198765432198, 100000000);
|
GncRational a(123456789987654321, 1000000000);
|
||||||
GncRational c = a + b;
|
GncRational b(65432198765432198, 100000000);
|
||||||
EXPECT_EQ (777778777641976301, c.m_num);
|
GncRational c = a + b;
|
||||||
EXPECT_EQ (1000000000, c.m_den);
|
EXPECT_EQ (777778777641976301, c.m_num);
|
||||||
EXPECT_EQ (GNC_ERROR_OK, c.m_error);
|
EXPECT_EQ (1000000000, c.m_den);
|
||||||
a += b;
|
a += b;
|
||||||
EXPECT_EQ (777778777641976301, a.m_num);
|
EXPECT_EQ (777778777641976301, a.m_num);
|
||||||
EXPECT_EQ (1000000000, a.m_den);
|
EXPECT_EQ (1000000000, a.m_den);
|
||||||
EXPECT_EQ (GNC_ERROR_OK, a.m_error);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(gncrational_operators, test_subtraction)
|
TEST(gncrational_operators, test_subtraction)
|
||||||
{
|
{
|
||||||
GncRational a(123456789987654321, 1000000000);
|
EXPECT_NO_THROW({
|
||||||
GncRational b(65432198765432198, 100000000);
|
GncRational a(123456789987654321, 1000000000);
|
||||||
GncRational c = a - b;
|
GncRational b(65432198765432198, 100000000);
|
||||||
EXPECT_EQ (-530865197666667659, c.m_num);
|
GncRational c = a - b;
|
||||||
EXPECT_TRUE(c.m_num.isNeg());
|
EXPECT_EQ (-530865197666667659, c.m_num);
|
||||||
EXPECT_EQ (1000000000, c.m_den);
|
EXPECT_TRUE(c.m_num.isNeg());
|
||||||
EXPECT_EQ (GNC_ERROR_OK, c.m_error);
|
EXPECT_EQ (1000000000, c.m_den);
|
||||||
c = b - a;
|
c = b - a;
|
||||||
EXPECT_EQ (530865197666667659, c.m_num);
|
EXPECT_EQ (530865197666667659, c.m_num);
|
||||||
EXPECT_FALSE(c.m_num.isNeg());
|
EXPECT_FALSE(c.m_num.isNeg());
|
||||||
EXPECT_EQ (1000000000, c.m_den);
|
EXPECT_EQ (1000000000, c.m_den);
|
||||||
EXPECT_EQ (GNC_ERROR_OK, c.m_error);
|
a -= b;
|
||||||
a -= b;
|
EXPECT_EQ (-530865197666667659, a.m_num);
|
||||||
EXPECT_EQ (-530865197666667659, a.m_num);
|
EXPECT_TRUE(a.m_num.isNeg());
|
||||||
EXPECT_TRUE(a.m_num.isNeg());
|
EXPECT_EQ (1000000000, a.m_den);
|
||||||
EXPECT_EQ (1000000000, a.m_den);
|
});
|
||||||
EXPECT_EQ (GNC_ERROR_OK, a.m_error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(gncrational_operators, test_multiplication)
|
TEST(gncrational_operators, test_multiplication)
|
||||||
{
|
{
|
||||||
GncRational a(123456789987654321, 1000000000);
|
EXPECT_NO_THROW({
|
||||||
GncRational b(65432198765432198, 100000000);
|
GncRational a(123456789987654321, 1000000000);
|
||||||
GncRational c = a * b;
|
GncRational b(65432198765432198, 100000000);
|
||||||
EXPECT_EQ (GncInt128(UINT64_C(437911925765117),
|
GncRational c = a * b;
|
||||||
UINT64_C(8081008345983448486)), c.m_num);
|
EXPECT_EQ (GncInt128(UINT64_C(437911925765117),
|
||||||
EXPECT_EQ (100000000000000000, c.m_den);
|
UINT64_C(8081008345983448486)), c.m_num);
|
||||||
EXPECT_EQ (GNC_ERROR_OK, c.m_error);
|
EXPECT_EQ (100000000000000000, c.m_den);
|
||||||
a *= b;
|
a *= b;
|
||||||
EXPECT_EQ (GncInt128(UINT64_C(437911925765117),
|
EXPECT_EQ (GncInt128(UINT64_C(437911925765117),
|
||||||
UINT64_C(8081008345983448486)), a.m_num);
|
UINT64_C(8081008345983448486)), a.m_num);
|
||||||
EXPECT_EQ (100000000000000000, a.m_den);
|
EXPECT_EQ (100000000000000000, a.m_den);
|
||||||
EXPECT_EQ (GNC_ERROR_OK, a.m_error);
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(gncrational_operators, test_division)
|
TEST(gncrational_operators, test_division)
|
||||||
{
|
{
|
||||||
GncRational a(123456789987654321, 1000000000);
|
EXPECT_NO_THROW({
|
||||||
GncRational b(65432198765432198, 100000000);
|
GncRational a(123456789987654321, 1000000000);
|
||||||
GncRational c = a / b;
|
GncRational b(65432198765432198, 100000000);
|
||||||
EXPECT_EQ (GncInt128(UINT64_C(669260), UINT64_C(11059994577585475840)),
|
GncRational c = a / b;
|
||||||
c.m_num);
|
EXPECT_EQ (GncInt128(UINT64_C(669260),
|
||||||
EXPECT_EQ (GncInt128(UINT64_C(3547086), UINT64_C(11115994079396609024)),
|
UINT64_C(11059994577585475840)), c.m_num);
|
||||||
c.m_den);
|
EXPECT_EQ (GncInt128(UINT64_C(3547086),
|
||||||
EXPECT_EQ (GNC_ERROR_OK, c.m_error);
|
UINT64_C(11115994079396609024)), c.m_den);
|
||||||
|
a /= b;
|
||||||
a /= b;
|
EXPECT_EQ (GncInt128(UINT64_C(669260),
|
||||||
EXPECT_EQ (GncInt128(UINT64_C(669260), UINT64_C(11059994577585475840)),
|
UINT64_C(11059994577585475840)), a.m_num);
|
||||||
a.m_num);
|
EXPECT_EQ (GncInt128(UINT64_C(3547086),
|
||||||
EXPECT_EQ (GncInt128(UINT64_C(3547086), UINT64_C(11115994079396609024)),
|
UINT64_C(11115994079396609024)), a.m_den);
|
||||||
a.m_den);
|
});
|
||||||
EXPECT_EQ (GNC_ERROR_OK, c.m_error);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(gncrational_functions, test_round_to_numeric)
|
TEST(gncrational_functions, test_round_to_numeric)
|
||||||
|
Loading…
Reference in New Issue
Block a user