diff options
-rw-r--r-- | python/py_amount.cc | 73 | ||||
-rw-r--r-- | python/py_value.cc | 7 | ||||
-rw-r--r-- | src/amount.cc | 584 | ||||
-rw-r--r-- | src/amount.h | 53 | ||||
-rw-r--r-- | src/balance.h | 29 | ||||
-rw-r--r-- | src/commodity.cc | 4 | ||||
-rw-r--r-- | src/entry.cc | 2 | ||||
-rw-r--r-- | src/filters.cc | 12 | ||||
-rw-r--r-- | src/gnucash.cc | 6 | ||||
-rw-r--r-- | src/value.cc | 38 | ||||
-rw-r--r-- | src/value.h | 8 | ||||
-rw-r--r-- | test/unit/t_amount.cc | 219 | ||||
-rw-r--r-- | test/unit/t_amount.h | 5 | ||||
-rw-r--r-- | test/unit/t_commodity.cc | 13 |
14 files changed, 159 insertions, 894 deletions
diff --git a/python/py_amount.cc b/python/py_amount.cc index b57687f2..2528f779 100644 --- a/python/py_amount.cc +++ b/python/py_amount.cc @@ -41,29 +41,6 @@ namespace ledger { using namespace boost::python; -#ifdef INTEGER_MATH -amount_t py_round_0(const amount_t& amount) { - return amount.round(); -} -amount_t py_round_1(const amount_t& amount, amount_t::precision_t prec) { - return amount.round(prec); -} -#endif - -double py_to_double_0(amount_t& amount) { - return amount.to_double(); -} -double py_to_double_1(amount_t& amount, bool no_check) { - return amount.to_double(no_check); -} - -long py_to_long_0(amount_t& amount) { - return amount.to_long(); -} -long py_to_long_1(amount_t& amount, bool no_check) { - return amount.to_long(no_check); -} - boost::optional<amount_t> py_value_0(const amount_t& amount) { return amount.value(); } @@ -169,7 +146,9 @@ void export_amount() make_getter(&amount_t::stream_fullstrings), make_setter(&amount_t::stream_fullstrings)) +#if 0 .def(init<double>()) +#endif .def(init<long>()) .def(init<std::string>()) @@ -185,80 +164,108 @@ internal precision.") .def(self == self) .def(self == long()) .def(long() == self) +#if 0 .def(self == double()) .def(double() == self) +#endif .def(self != self) .def(self != long()) .def(long() != self) +#if 0 .def(self != double()) .def(double() != self) +#endif .def(! self) .def(self < self) .def(self < long()) .def(long() < self) +#if 0 .def(self < double()) .def(double() < self) +#endif .def(self <= self) .def(self <= long()) .def(long() <= self) +#if 0 .def(self <= double()) .def(double() <= self) +#endif .def(self > self) .def(self > long()) .def(long() > self) +#if 0 .def(self > double()) .def(double() > self) +#endif .def(self >= self) .def(self >= long()) .def(long() >= self) +#if 0 .def(self >= double()) .def(double() >= self) +#endif .def(self += self) .def(self += long()) +#if 0 .def(self += double()) +#endif .def(self + self) .def(self + long()) .def(long() + self) +#if 0 .def(self + double()) .def(double() + self) +#endif .def(self -= self) .def(self -= long()) +#if 0 .def(self -= double()) +#endif .def(self - self) .def(self - long()) .def(long() - self) +#if 0 .def(self - double()) .def(double() - self) +#endif .def(self *= self) .def(self *= long()) +#if 0 .def(self *= double()) +#endif .def(self * self) .def(self * long()) .def(long() * self) +#if 0 .def(self * double()) .def(double() * self) +#endif .def(self /= self) .def(self /= long()) +#if 0 .def(self /= double()) +#endif .def(self / self) .def(self / long()) .def(long() / self) +#if 0 .def(self / double()) .def(double() / self) +#endif .def("precision", &amount_t::precision) @@ -270,11 +277,8 @@ internal precision.") .def("abs", &amount_t::abs) .def("__abs__", &amount_t::abs) -#ifdef INTEGER_MATH - .def("round", py_round_0) - .def("round", py_round_1) -#endif - .def("unround", &amount_t::unround) + .def("rounded", &amount_t::rounded) + .def("unrounded", &amount_t::unrounded) .def("reduce", &amount_t::reduce) .def("in_place_reduce", &amount_t::in_place_reduce, @@ -295,18 +299,15 @@ internal precision.") .def("is_realzero", &amount_t::is_realzero) .def("is_null", &amount_t::is_null) - .def("to_double", py_to_double_0) - .def("to_double", py_to_double_1) - .def("__float__", py_to_double_0) - .def("to_long", py_to_long_0) - .def("to_long", py_to_long_1) - .def("__int__", py_to_long_0) + .def("to_double", &amount_t::to_double) + .def("__float__", &amount_t::to_double) + .def("to_long", &amount_t::to_long) + .def("__int__", &amount_t::to_long) .def("to_string", &amount_t::to_string) .def("__str__", &amount_t::to_string) .def("to_fullstring", &amount_t::to_fullstring) .def("__repr__", &amount_t::to_fullstring) - .def("fits_in_double", &amount_t::fits_in_double) .def("fits_in_long", &amount_t::fits_in_long) .def("quantity_string", &amount_t::quantity_string) @@ -359,7 +360,9 @@ internal precision.") register_optional_to_python<amount_t>(); +#if 0 implicitly_convertible<double, amount_t>(); +#endif implicitly_convertible<long, amount_t>(); implicitly_convertible<string, amount_t>(); diff --git a/python/py_value.cc b/python/py_value.cc index 48cd0feb..4556c31e 100644 --- a/python/py_value.cc +++ b/python/py_value.cc @@ -195,11 +195,8 @@ void export_value() .def("abs", &value_t::abs) .def("__abs__", &value_t::abs) -#ifdef INTEGER_MATH - .def("round", &value_t::round) - .def("in_place_round", &value_t::in_place_round) -#endif - .def("unround", &value_t::unround) + .def("rounded", &value_t::rounded) + .def("unrounded", &value_t::unrounded) .def("reduce", &value_t::reduce) .def("in_place_reduce", &value_t::in_place_reduce) diff --git a/src/amount.cc b/src/amount.cc index bc7d5a6a..ae61495c 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -47,26 +47,18 @@ bool amount_t::stream_fullstrings = false; #if !defined(THREADSAFE) // These global temporaries are pre-initialized for the sake of // efficiency, and are reused over and over again. -static mpz_t temp; +static mpz_t temp; +static mpq_t tempq; static mpfr_t tempf; -#ifdef INTEGER_MATH -static mpz_t divisor; -#else -static mpq_t tempq; static mpfr_t tempfb; #endif -#endif struct amount_t::bigint_t : public supports_flags<> { #define BIGINT_BULK_ALLOC 0x01 #define BIGINT_KEEP_PREC 0x02 -#ifdef INTEGER_MATH - mpz_t val; -#else mpq_t val; -#endif precision_t prec; uint_least16_t ref; uint_fast32_t index; @@ -75,31 +67,19 @@ struct amount_t::bigint_t : public supports_flags<> bigint_t() : prec(0), ref(1), index(0) { TRACE_CTOR(bigint_t, ""); -#ifdef INTEGER_MATH - mpz_init(val); -#else mpq_init(val); -#endif } bigint_t(const bigint_t& other) : supports_flags<>(other.flags() & ~BIGINT_BULK_ALLOC), prec(other.prec), ref(1), index(0) { TRACE_CTOR(bigint_t, "copy"); -#ifdef INTEGER_MATH - mpz_init_set(val, other.val); -#else mpq_init(val); mpq_set(val, other.val); -#endif } ~bigint_t() { TRACE_DTOR(bigint_t); assert(ref == 0); -#ifdef INTEGER_MATH - mpz_clear(val); -#else mpq_clear(val); -#endif } bool valid() const { @@ -125,15 +105,11 @@ amount_t * one = NULL; void amount_t::initialize() { mpz_init(temp); - mpfr_init(tempf); -#ifdef INTEGER_MATH - mpz_init(divisor); -#else mpq_init(tempq); + mpfr_init(tempf); mpfr_init(tempfb); -#endif - one = new amount_t(amount_t(1L).unround()); + one = new amount_t(amount_t(1L).unrounded()); if (! current_pool) current_pool = new commodity_pool_t; @@ -153,13 +129,9 @@ void amount_t::initialize() void amount_t::shutdown() { mpz_clear(temp); - mpfr_clear(tempf); -#ifdef INTEGER_MATH - mpz_clear(divisor); -#else mpq_clear(tempq); + mpfr_clear(tempf); mpfr_clear(tempfb); -#endif checked_delete(one); @@ -206,28 +178,6 @@ void amount_t::_dup() assert(valid()); } -#ifdef INTEGER_MATH - -void amount_t::_resize(precision_t prec) -{ - assert(prec < 256); - - if (! quantity || prec == quantity->prec) - return; - - _dup(); - - assert(prec > quantity->prec); - mpz_ui_pow_ui(divisor, 10, prec - quantity->prec); - mpz_mul(MP(quantity), MP(quantity), divisor); - - quantity->prec = prec; - - assert(valid()); -} - -#endif // INTEGER_MATH - void amount_t::_clear() { if (quantity) { @@ -262,12 +212,7 @@ amount_t::amount_t(const double val) : commodity_(NULL) { TRACE_CTOR(amount_t, "const double"); quantity = new bigint_t; -#ifdef INTEGER_MATH - mpfr_set_d(tempf, val, GMP_RNDN); - mpfr_get_z(MP(quantity), tempf); -#else mpq_set_d(MP(quantity), val); -#endif quantity->prec = extend_by_digits; // an approximation } @@ -275,22 +220,14 @@ amount_t::amount_t(const unsigned long val) : commodity_(NULL) { TRACE_CTOR(amount_t, "const unsigned long"); quantity = new bigint_t; -#ifdef INTEGER_MATH - mpz_set_ui(MP(quantity), val); -#else mpq_set_ui(MP(quantity), val, 1); -#endif } amount_t::amount_t(const long val) : commodity_(NULL) { TRACE_CTOR(amount_t, "const long"); quantity = new bigint_t; -#ifdef INTEGER_MATH - mpz_set_si(MP(quantity), val); -#else mpq_set_si(MP(quantity), val, 1); -#endif } @@ -325,23 +262,7 @@ int amount_t::compare(const amount_t& amt) const "Cannot compare amounts with different commodities: " << commodity().symbol() << " and " << amt.commodity().symbol()); -#ifdef INTEGER_MATH - if (quantity->prec == amt.quantity->prec) { - return mpz_cmp(MP(quantity), MP(amt.quantity)); - } - else if (quantity->prec < amt.quantity->prec) { - amount_t t(*this); - t._resize(amt.quantity->prec); - return mpz_cmp(MP(t.quantity), MP(amt.quantity)); - } - else { - amount_t t = amt; - t._resize(quantity->prec); - return mpz_cmp(MP(quantity), MP(t.quantity)); - } -#else return mpq_cmp(MP(quantity), MP(amt.quantity)); -#endif } @@ -367,25 +288,10 @@ amount_t& amount_t::operator+=(const amount_t& amt) _dup(); -#ifdef INTEGER_MATH - if (quantity->prec == amt.quantity->prec) { - mpz_add(MP(quantity), MP(quantity), MP(amt.quantity)); - } - else if (quantity->prec < amt.quantity->prec) { - _resize(amt.quantity->prec); - mpz_add(MP(quantity), MP(quantity), MP(amt.quantity)); - } - else { - amount_t t = amt; - t._resize(quantity->prec); - mpz_add(MP(quantity), MP(quantity), MP(t.quantity)); - } -#else mpq_add(MP(quantity), MP(quantity), MP(amt.quantity)); if (quantity->prec < amt.quantity->prec) quantity->prec = amt.quantity->prec; -#endif return *this; } @@ -412,81 +318,14 @@ amount_t& amount_t::operator-=(const amount_t& amt) _dup(); -#ifdef INTEGER_MATH - if (quantity->prec == amt.quantity->prec) { - mpz_sub(MP(quantity), MP(quantity), MP(amt.quantity)); - } - else if (quantity->prec < amt.quantity->prec) { - _resize(amt.quantity->prec); - mpz_sub(MP(quantity), MP(quantity), MP(amt.quantity)); - } - else { - amount_t t = amt; - t._resize(quantity->prec); - mpz_sub(MP(quantity), MP(quantity), MP(t.quantity)); - } -#else mpq_sub(MP(quantity), MP(quantity), MP(amt.quantity)); if (quantity->prec < amt.quantity->prec) quantity->prec = amt.quantity->prec; -#endif return *this; } -#ifdef INTEGER_MATH - -namespace { - void mpz_round(mpz_t out, mpz_t value, int value_prec, int round_prec) - { - // Round `value', with an encoding precision of `value_prec', to a - // rounded value with precision `round_prec'. Result is stored in - // `out'. - - assert(value_prec > round_prec); - - mpz_t quotient; - mpz_t remainder; - - mpz_init(quotient); - mpz_init(remainder); - - mpz_ui_pow_ui(divisor, 10, value_prec - round_prec); - mpz_tdiv_qr(quotient, remainder, value, divisor); - mpz_divexact_ui(divisor, divisor, 10); - mpz_mul_ui(divisor, divisor, 5); - - if (mpz_sgn(remainder) < 0) { - mpz_neg(divisor, divisor); - if (mpz_cmp(remainder, divisor) < 0) { - mpz_ui_pow_ui(divisor, 10, value_prec - round_prec); - mpz_add(remainder, divisor, remainder); - mpz_ui_sub(remainder, 0, remainder); - mpz_add(out, value, remainder); - } else { - mpz_sub(out, value, remainder); - } - } else { - if (mpz_cmp(remainder, divisor) >= 0) { - mpz_ui_pow_ui(divisor, 10, value_prec - round_prec); - mpz_sub(remainder, divisor, remainder); - mpz_add(out, value, remainder); - } else { - mpz_sub(out, value, remainder); - } - } - mpz_clear(quotient); - mpz_clear(remainder); - - // chop off the rounded bits - mpz_ui_pow_ui(divisor, 10, value_prec - round_prec); - mpz_tdiv_q(out, out, divisor); - } -} - -#endif // INTEGER_MATH - amount_t& amount_t::operator*=(const amount_t& amt) { assert(amt.valid()); @@ -502,11 +341,7 @@ amount_t& amount_t::operator*=(const amount_t& amt) _dup(); -#ifdef INTEGER_MATH - mpz_mul(MP(quantity), MP(quantity), MP(amt.quantity)); -#else mpq_mul(MP(quantity), MP(quantity), MP(amt.quantity)); -#endif quantity->prec += amt.quantity->prec; if (! has_commodity()) @@ -514,13 +349,8 @@ amount_t& amount_t::operator*=(const amount_t& amt) if (has_commodity() && ! keep_precision()) { precision_t comm_prec = commodity().precision(); - if (quantity->prec > comm_prec + extend_by_digits) { -#ifdef INTEGER_MATH - mpz_round(MP(quantity), MP(quantity), quantity->prec, - comm_prec + extend_by_digits); -#endif // INTEGER_MATH + if (quantity->prec > comm_prec + extend_by_digits) quantity->prec = comm_prec + extend_by_digits; - } } return *this; @@ -547,19 +377,8 @@ amount_t& amount_t::operator/=(const amount_t& amt) // Increase the value's precision, to capture fractional parts after // the divide. Round up in the last position. -#ifdef INTEGER_MATH - mpz_ui_pow_ui(divisor, 10, (2 * amt.quantity->prec) + quantity->prec + - extend_by_digits + 1U); - mpz_mul(MP(quantity), MP(quantity), divisor); - mpz_tdiv_q(MP(quantity), MP(quantity), MP(amt.quantity)); - quantity->prec += amt.quantity->prec + quantity->prec + extend_by_digits + 1U; - - mpz_round(MP(quantity), MP(quantity), quantity->prec, quantity->prec - 1); - quantity->prec -= 1; -#else mpq_div(MP(quantity), MP(quantity), MP(amt.quantity)); quantity->prec += amt.quantity->prec + quantity->prec + extend_by_digits; -#endif if (! has_commodity()) commodity_ = amt.commodity_; @@ -571,13 +390,8 @@ amount_t& amount_t::operator/=(const amount_t& amt) if (has_commodity() && ! keep_precision()) { precision_t comm_prec = commodity().precision(); - if (quantity->prec > comm_prec + extend_by_digits) { -#ifdef INTEGER_MATH - mpz_round(MP(quantity), MP(quantity), quantity->prec, - comm_prec + extend_by_digits); -#endif // INTEGER_MATH + if (quantity->prec > comm_prec + extend_by_digits) quantity->prec = comm_prec + extend_by_digits; - } } return *this; @@ -634,59 +448,28 @@ amount_t& amount_t::in_place_negate() { if (quantity) { _dup(); -#ifdef INTEGER_MATH - mpz_neg(MP(quantity), MP(quantity)); -#else mpq_neg(MP(quantity), MP(quantity)); -#endif } else { throw_(amount_error, "Cannot negate an uninitialized amount"); } return *this; } -#ifdef INTEGER_MATH - -amount_t& amount_t::in_place_round() -{ - if (! quantity) - throw_(amount_error, "Cannot round an uninitialized amount"); - - if (has_commodity()) - in_place_round(commodity().precision()); - - return *this; -} - -amount_t& amount_t::in_place_round(precision_t prec) +amount_t amount_t::rounded() const { if (! quantity) - throw_(amount_error, "Cannot round an uninitialized amount"); - - if (quantity && quantity->prec <= prec) { - if (keep_precision()) { - _dup(); - set_keep_precision(false); - } + throw_(amount_error, "Cannot set rounding for an uninitialized amount"); + else if (! keep_precision()) return *this; - } - - DEBUG("amount.round", "Rounding " << *this << " to precision " << prec); - - _dup(); - mpz_round(MP(quantity), MP(quantity), quantity->prec, prec); - - quantity->prec = prec; - set_keep_precision(false); - DEBUG("amount.round", " result = " << *this); + amount_t t(*this); + t._dup(); + t.set_keep_precision(false); - return *this; + return t; } -#endif // INTEGER_MATH - -amount_t amount_t::unround() const +amount_t amount_t::unrounded() const { if (! quantity) throw_(amount_error, "Cannot unround an uninitialized amount"); @@ -732,11 +515,7 @@ optional<amount_t> amount_t::value(const optional<datetime_t>& moment, if (quantity) { optional<price_point_t> point(commodity().find_price(in_terms_of, moment)); if (point) -#ifdef INTEGER_MATH - return (point->price * number()).round(); -#else - return point->price * number(); -#endif + return (point->price * number()).rounded(); } else { throw_(amount_error, "Cannot determine value of an uninitialized amount"); } @@ -749,15 +528,9 @@ int amount_t::sign() const if (! quantity) throw_(amount_error, "Cannot determine sign of an uninitialized amount"); -#ifdef INTEGER_MATH - return mpz_sgn(MP(quantity)); -#else return mpq_sgn(MP(quantity)); -#endif } -#ifndef INTEGER_MATH - namespace { void stream_out_mpq(std::ostream& out, mpq_t quant, amount_t::precision_t prec, @@ -826,8 +599,6 @@ namespace { } } -#endif // INTEGER_MATH - bool amount_t::is_zero() const { if (! quantity) @@ -837,9 +608,6 @@ bool amount_t::is_zero() const if (keep_precision() || quantity->prec <= commodity().precision()) { return is_realzero(); } else { -#ifdef INTEGER_MATH - return round(commodity().precision()).sign() == 0; -#else std::ostringstream out; stream_out_mpq(out, MP(quantity), commodity().precision()); @@ -847,80 +615,34 @@ bool amount_t::is_zero() const if (*p != '0' && *p != '.') return false; return true; -#endif } } return is_realzero(); } -double amount_t::to_double(bool no_check) const +double amount_t::to_double() const { if (! quantity) throw_(amount_error, "Cannot convert an uninitialized amount to a double"); -#ifdef INTEGER_MATH - mpz_t remainder; - mpz_init(remainder); - - mpz_set(temp, MP(quantity)); - mpz_ui_pow_ui(divisor, 10, quantity->prec); - mpz_tdiv_qr(temp, remainder, temp, divisor); - - char * quotient_s = mpz_get_str(NULL, 10, temp); - char * remainder_s = mpz_get_str(NULL, 10, remainder); - - std::ostringstream num; - num << quotient_s << '.' << remainder_s; - - std::free(quotient_s); - std::free(remainder_s); - - mpz_clear(remainder); - - double value = lexical_cast<double>(num.str()); -#else mpfr_set_q(tempf, MP(quantity), GMP_RNDN); - double value = mpfr_get_d(tempf, GMP_RNDN); -#endif - - if (! no_check && *this != value) - throw_(amount_error, "Conversion of amount to_double loses precision"); - - return value; + return mpfr_get_d(tempf, GMP_RNDN); } -long amount_t::to_long(bool no_check) const +long amount_t::to_long() const { if (! quantity) throw_(amount_error, "Cannot convert an uninitialized amount to a long"); -#ifdef INTEGER_MATH - mpz_set(temp, MP(quantity)); - mpz_ui_pow_ui(divisor, 10, quantity->prec); - mpz_tdiv_q(temp, temp, divisor); - long value = mpz_get_si(temp); -#else mpfr_set_q(tempf, MP(quantity), GMP_RNDN); - long value = mpfr_get_si(tempf, GMP_RNDN); -#endif - - if (! no_check && *this != value) - throw_(amount_error, "Conversion of amount to_long loses precision"); - - return value; -} - -bool amount_t::fits_in_double() const -{ - double value = to_double(true); - return *this == amount_t(value); + return mpfr_get_si(tempf, GMP_RNDN); } bool amount_t::fits_in_long() const { - long value = to_long(true); - return *this == amount_t(value); + mpfr_set_q(tempf, MP(quantity), GMP_RNDN); + return mpfr_fits_slong_p(tempf, GMP_RNDN); } @@ -1170,9 +892,6 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags) } *t = '\0'; -#ifdef INTEGER_MATH - mpz_set_str(MP(quantity), buf.get(), 10); -#else mpq_set_str(MP(quantity), buf.get(), 10); mpz_ui_pow_ui(temp, 10, quantity->prec); mpq_set_z(tempq, temp); @@ -1183,13 +902,8 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags) DEBUG("amount.parse", "Rational parsed = " << buf); std::free(buf); } -#endif } else { -#ifdef INTEGER_MATH - mpz_set_str(MP(quantity), quant.c_str(), 10); -#else mpq_set_str(MP(quantity), quant.c_str(), 10); -#endif } if (negative) @@ -1243,156 +957,6 @@ void amount_t::print(std::ostream& _out, bool omit_commodity, commodity_t& comm(base.commodity()); precision_t precision = 0; -#ifdef INTEGER_MATH - - mpz_t quotient; - mpz_t rquotient; - mpz_t remainder; - - mpz_init(quotient); - mpz_init(rquotient); - mpz_init(remainder); - - bool negative = false; - - // Ensure the value is rounded to the commodity's precision before - // outputting it. NOTE: `rquotient' is used here as a temp variable! - - if (quantity) { - if (! comm || full_precision || base.keep_precision()) { - mpz_ui_pow_ui(divisor, 10, base.quantity->prec); - mpz_tdiv_qr(quotient, remainder, MP(base.quantity), divisor); - precision = base.quantity->prec; - } - else if (comm.precision() < base.quantity->prec) { - mpz_round(rquotient, MP(base.quantity), base.quantity->prec, - comm.precision()); - mpz_ui_pow_ui(divisor, 10, comm.precision()); - mpz_tdiv_qr(quotient, remainder, rquotient, divisor); - precision = comm.precision(); - } - else if (comm.precision() > base.quantity->prec) { - mpz_ui_pow_ui(divisor, 10, comm.precision() - base.quantity->prec); - mpz_mul(rquotient, MP(base.quantity), divisor); - mpz_ui_pow_ui(divisor, 10, comm.precision()); - mpz_tdiv_qr(quotient, remainder, rquotient, divisor); - precision = comm.precision(); - } - else if (base.quantity->prec) { - mpz_ui_pow_ui(divisor, 10, base.quantity->prec); - mpz_tdiv_qr(quotient, remainder, MP(base.quantity), divisor); - precision = base.quantity->prec; - } - else { - mpz_set(quotient, MP(base.quantity)); - mpz_set_ui(remainder, 0); - precision = 0; - } - - if (mpz_sgn(quotient) < 0 || mpz_sgn(remainder) < 0) { - negative = true; - - mpz_abs(quotient, quotient); - mpz_abs(remainder, remainder); - } - mpz_set(rquotient, remainder); - } - - if (! omit_commodity && ! comm.has_flags(COMMODITY_STYLE_SUFFIXED)) { - comm.print(out); - if (comm.has_flags(COMMODITY_STYLE_SEPARATED)) - out << " "; - } - - if (negative) - out << "-"; - - if (! quantity || mpz_sgn(quotient) == 0) { - out << '0'; - } - else if (omit_commodity || ! comm.has_flags(COMMODITY_STYLE_THOUSANDS)) { - char * p = mpz_get_str(NULL, 10, quotient); - out << p; - std::free(p); - } - else { - std::list<string> strs; - char buf[4]; - - for (int powers = 0; true; powers += 3) { - if (powers > 0) { - mpz_ui_pow_ui(divisor, 10, powers); - mpz_tdiv_q(temp, quotient, divisor); - if (mpz_sgn(temp) == 0) - break; - mpz_tdiv_r_ui(temp, temp, 1000); - } else { - mpz_tdiv_r_ui(temp, quotient, 1000); - } - mpz_get_str(buf, 10, temp); - strs.push_back(buf); - } - - bool printed = false; - - for (std::list<string>::reverse_iterator i = strs.rbegin(); - i != strs.rend(); - i++) { - if (printed) { - out << (comm.has_flags(COMMODITY_STYLE_EUROPEAN) ? '.' : ','); - out.width(3); - out.fill('0'); - } - out << *i; - - printed = true; - } - } - - if (quantity && precision) { - std::ostringstream final; - final.width(precision); - final.fill('0'); - char * p = mpz_get_str(NULL, 10, rquotient); - final << p; - std::free(p); - - const string& str(final.str()); - int i, len = str.length(); - const char * q = str.c_str(); - for (i = len; i > 0; i--) - if (q[i - 1] != '0') - break; - - string ender; - if (i == len) - ender = str; - else if (i < comm.precision()) - ender = string(str, 0, comm.precision()); - else - ender = string(str, 0, i); - - if (! ender.empty()) { - if (omit_commodity) - out << '.'; - else - out << (comm.has_flags(COMMODITY_STYLE_EUROPEAN) ? ',' : '.'); - out << ender; - } - } - - if (! omit_commodity && comm.has_flags(COMMODITY_STYLE_SUFFIXED)) { - if (comm.has_flags(COMMODITY_STYLE_SEPARATED)) - out << " "; - comm.print(out); - } - - mpz_clear(quotient); - mpz_clear(rquotient); - mpz_clear(remainder); - -#else // INTEGER_MATH - if (! omit_commodity && ! comm.has_flags(COMMODITY_STYLE_SUFFIXED)) { comm.print(out); if (comm.has_flags(COMMODITY_STYLE_SEPARATED)) @@ -1408,8 +972,6 @@ void amount_t::print(std::ostream& _out, bool omit_commodity, comm.print(out); } -#endif // INTEGER_MATH - // If there are any annotations associated with this commodity, // output them now. @@ -1451,43 +1013,27 @@ void amount_t::read(std::istream& in) if (byte < 3) { quantity = new bigint_t; -#ifndef INTEGER_MATH - mpz_t numerator; - mpz_t denominator; -#endif - unsigned short len; in.read(reinterpret_cast<char *>(&len), sizeof(len)); assert(len < 4096); static char buf[4096]; in.read(buf, len); -#ifdef INTEGER_MATH - mpz_import(MP(quantity), len / sizeof(short), 1, sizeof(short), - 0, 0, buf); -#else - mpz_init(numerator); - mpz_import(numerator, len / sizeof(short), 1, sizeof(short), + + mpz_import(temp, len / sizeof(short), 1, sizeof(short), 0, 0, buf); + mpq_set_num(MP(quantity), temp); in.read(reinterpret_cast<char *>(&len), sizeof(len)); assert(len < 4096); in.read(buf, len); - mpz_init(denominator); - mpz_import(denominator, len / sizeof(short), 1, sizeof(short), + mpz_import(temp, len / sizeof(short), 1, sizeof(short), 0, 0, buf); - - mpq_set_num(MP(quantity), numerator); - mpq_set_den(MP(quantity), denominator); -#endif + mpq_set_den(MP(quantity), temp); char negative; in.read(&negative, sizeof(negative)); if (negative) -#ifdef INTEGER_MATH - mpz_neg(MP(quantity), MP(quantity)); -#else mpq_neg(MP(quantity), MP(quantity)); -#endif in.read(reinterpret_cast<char *>(&quantity->prec), sizeof(quantity->prec)); @@ -1531,40 +1077,28 @@ void amount_t::read(const char *& data, quantity = new bigint_t; } -#ifndef INTEGER_MATH - mpz_t numerator; - mpz_t denominator; -#endif - unsigned short len = *reinterpret_cast<unsigned short *>(const_cast<char *>(data)); data += sizeof(unsigned short); -#ifdef INTEGER_MATH - mpz_import(MP(quantity), len / sizeof(short), 1, sizeof(short), - 0, 0, data); -#else - mpz_init(numerator); - mpz_import(numerator, len / sizeof(short), 1, sizeof(short), + mpz_init(temp); + mpz_import(temp, len / sizeof(short), 1, sizeof(short), 0, 0, data); + data += len; + + mpq_set_num(MP(quantity), temp); len = *reinterpret_cast<unsigned short *>(const_cast<char *>(data)); data += sizeof(unsigned short); - mpz_init(denominator); - mpz_import(denominator, len / sizeof(short), 1, sizeof(short), + mpz_init(temp); + mpz_import(temp, len / sizeof(short), 1, sizeof(short), 0, 0, data); - - mpq_set_num(MP(quantity), numerator); - mpq_set_den(MP(quantity), denominator); -#endif data += len; + mpq_set_den(MP(quantity), temp); + char negative = *data++; if (negative) -#ifdef INTEGER_MATH - mpz_neg(MP(quantity), MP(quantity)); -#else mpq_neg(MP(quantity), MP(quantity)); -#endif quantity->prec = *reinterpret_cast<precision_t *>(const_cast<char *>(data)); data += sizeof(precision_t); @@ -1585,6 +1119,20 @@ void amount_t::read(const char *& data, } } +namespace { + void write_bytes(std::ostream& out, + const char * buf, + const std::size_t size) + { + unsigned short len = size * sizeof(short); + out.write(reinterpret_cast<char *>(&len), sizeof(len)); + if (len) { + assert(len < 4096); + out.write(buf, len); + } + } +} + void amount_t::write(std::ostream& out, std::size_t index) const { using namespace ledger::binary; @@ -1614,32 +1162,16 @@ void amount_t::write(std::ostream& out, std::size_t index) const std::size_t size; static char buf[4096]; -#ifdef INTEGER_MATH - mpz_export(buf, &size, 1, sizeof(short), 0, 0, MP(quantity)); -#else - mpz_t numerator; - mpz_t denominator; - - mpz_init(numerator); - mpq_get_num(numerator, MP(quantity)); - mpz_export(buf, &size, 1, sizeof(short), 0, 0, numerator); - - mpz_init(denominator); - mpq_get_den(denominator, MP(quantity)); - mpz_export(buf, &size, 1, sizeof(short), 0, 0, denominator); -#endif - unsigned short len = size * sizeof(short); - out.write(reinterpret_cast<char *>(&len), sizeof(len)); - if (len) { - assert(len < 4096); - out.write(buf, len); - } -#ifdef INTEGER_MATH - byte = mpz_sgn(MP(quantity)) < 0 ? 1 : 0; -#else + mpq_get_num(temp, MP(quantity)); + mpz_export(buf, &size, 1, sizeof(short), 0, 0, temp); + write_bytes(out, buf, size); + + mpq_get_den(temp, MP(quantity)); + mpz_export(buf, &size, 1, sizeof(short), 0, 0, temp); + write_bytes(out, buf, size); + byte = mpq_sgn(MP(quantity)) < 0 ? 1 : 0; -#endif out.write(&byte, sizeof(byte)); out.write(reinterpret_cast<char *>(&quantity->prec), sizeof(quantity->prec)); diff --git a/src/amount.h b/src/amount.h index d15a0205..7e4f832c 100644 --- a/src/amount.h +++ b/src/amount.h @@ -57,11 +57,6 @@ namespace ledger { -// If defined, amount.cc uses GMP integers rather than rationals. -// Ledger 3.0 uses rationals, but 2.6 and before used integers, so this -// provides a quick way of testing against past numerical behavior. -//#define INTEGER_MATH 1 - class commodity_t; class annotation_t; class commodity_pool_t; @@ -147,9 +142,6 @@ public: protected: void _copy(const amount_t& amt); void _dup(); -#ifdef INTEGER_MATH - void _resize(precision_t prec); -#endif void _clear(); void _release(); @@ -354,33 +346,16 @@ public: return *this; } -#ifdef INTEGER_MATH - - /** An amount's internal value to the given precision, or to the - commodity's current display precision if no precision value is - given. This method changes the internal value of the amount, if - it's internal precision was greater than the rounding precision. - */ - amount_t round() const { - amount_t temp(*this); - temp.in_place_round(); - return temp; - } - amount_t& in_place_round(); - - amount_t round(precision_t prec) const { - amount_t temp(*this); - temp.in_place_round(prec); - return temp; - } - amount_t& in_place_round(precision_t prec); - -#endif // INTEGER_MATH + /** Yields an amount whose display precision when output is truncated + to the display precision of its commodity. This is normally the + default state of an amount, but if one has become unrounded, this + sets the "keep precision" state back to false. + @see set_keep_precision */ + amount_t rounded() const; /** Yields an amount whose display precision is never truncated, even - though its commodity normally displays only rounded values. - */ - amount_t unround() const; + though its commodity normally displays only rounded values. */ + amount_t unrounded() const; /** reduces a value to its most basic commodity form, for amounts that utilize "scaling commodities". For example, an amount of \c 1h @@ -487,9 +462,6 @@ public: optional boolean argument is true (the default), an exception is thrown if the conversion would lose information. - fits_in_double() returns true if to_double() would not lose - precision. - fits_in_long() returns true if to_long() would not lose precision. @@ -506,15 +478,14 @@ public: been stripped and the full, internal precision of the amount would be displayed. */ - double to_double(bool no_check = false) const; - long to_long(bool no_check = false) const; + double to_double() const; + long to_long() const; + bool fits_in_long() const; + string to_string() const; string to_fullstring() const; string quantity_string() const; - bool fits_in_double() const; - bool fits_in_long() const; - /*@}*/ /** @name Commodity methods diff --git a/src/balance.h b/src/balance.h index eec86576..d1e4301b 100644 --- a/src/balance.h +++ b/src/balance.h @@ -311,38 +311,17 @@ public: return temp; } -#ifdef INTEGER_MATH - - balance_t round() const { + balance_t rounded() const { balance_t temp; foreach (const amounts_map::value_type& pair, amounts) - temp += pair.second.round(); + temp += pair.second.rounded(); return temp; } - balance_t& in_place_round() { - foreach (amounts_map::value_type& pair, amounts) - pair.second.in_place_round(); - return *this; - } - - balance_t round(amount_t::precision_t prec) const { - balance_t temp; - foreach (const amounts_map::value_type& pair, amounts) - temp += pair.second.round(prec); - return temp; - } - balance_t& in_place_round(amount_t::precision_t prec) { - foreach (amounts_map::value_type& pair, amounts) - pair.second.in_place_round(prec); - return *this; - } - -#endif // INTEGER_MATH - balance_t unround() const { + balance_t unrounded() const { balance_t temp; foreach (const amounts_map::value_type& pair, amounts) - temp += pair.second.unround(); + temp += pair.second.unrounded(); return temp; } diff --git a/src/commodity.cc b/src/commodity.cc index 0a751941..1157f3e7 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -657,15 +657,13 @@ void annotation_t::parse(std::istream& in) temp.parse(buf, amount_t::PARSE_NO_MIGRATE); temp.in_place_reduce(); -#ifdef INTEGER_MATH // Since this price will maintain its own precision, make sure // it is at least as large as the base commodity, since the user // may have only specified {$1} or something similar. if (temp.has_commodity() && temp.precision() > temp.commodity().precision()) - temp = temp.round(); // no need to retain individual precision -#endif + temp = temp.rounded(); // no need to retain individual precision price = temp; } diff --git a/src/entry.cc b/src/entry.cc index 9749b1df..d1aa1234 100644 --- a/src/entry.cc +++ b/src/entry.cc @@ -231,7 +231,7 @@ bool entry_base_t::finalize() add_error_context(entry_context(*this)); #endif add_error_context("Unbalanced remainder is: "); - add_error_context(value_context(balance.unround())); + add_error_context(value_context(balance.unrounded())); throw_(balance_error, "Entry does not balance"); } diff --git a/src/filters.cc b/src/filters.cc index 47dec09b..4b8c7162 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -367,11 +367,7 @@ void changed_value_xacts::output_diff(const date_t& date) value_t cur_bal; last_xact->xdata().date = date; -#ifdef INTEGER_MATH - cur_bal = total_expr.calc(*last_xact).round(); -#else - cur_bal = total_expr.calc(*last_xact); -#endif + cur_bal = total_expr.calc(*last_xact).rounded(); if (value_t diff = cur_bal - last_balance) { entry_temps.push_back(entry_t()); @@ -394,11 +390,7 @@ void changed_value_xacts::operator()(xact_t& xact) item_handler<xact_t>::operator()(xact); -#ifdef INTEGER_MATH - last_balance = total_expr.calc(xact).round(); -#else - last_balance = total_expr.calc(xact); -#endif + last_balance = total_expr.calc(xact).rounded(); last_xact = &xact; } diff --git a/src/gnucash.cc b/src/gnucash.cc index 91217699..29528013 100644 --- a/src/gnucash.cc +++ b/src/gnucash.cc @@ -187,11 +187,7 @@ static void endElement(void *, const char *name) if (default_commodity) { curr_quant.set_commodity(*default_commodity); -#ifdef INTEGER_MATH - value = curr_quant.round(); -#else - value = curr_quant; -#endif + value = curr_quant.rounded(); if (curr_value.commodity() == *default_commodity) curr_value = value; diff --git a/src/value.cc b/src/value.cc index b63b8d76..b5ee6602 100644 --- a/src/value.cc +++ b/src/value.cc @@ -1400,56 +1400,28 @@ value_t value_t::abs() const return NULL_VALUE; } -#ifdef INTEGER_MATH - -value_t value_t::round() const +value_t value_t::rounded() const { switch (type()) { case INTEGER: return *this; case AMOUNT: - return as_amount().round(); - case BALANCE: - return as_balance().round(); - case BALANCE_PAIR: - return as_balance_pair().round(); + return as_amount().rounded(); default: break; } - throw_(value_error, "Cannot round " << label()); + throw_(value_error, "Cannot set rounding for " << label()); return NULL_VALUE; } -void value_t::in_place_round() -{ - switch (type()) { - case INTEGER: - break; - case AMOUNT: - as_amount_lval().in_place_round(); - break; - case BALANCE: - as_balance_lval().in_place_round(); - break; - case BALANCE_PAIR: - as_balance_pair_lval().in_place_round(); - break; - default: - throw_(value_error, "Cannot round " << label()); - break; - } -} - -#endif // INTEGER_MATH - -value_t value_t::unround() const +value_t value_t::unrounded() const { switch (type()) { case INTEGER: return *this; case AMOUNT: - return as_amount().unround(); + return as_amount().unrounded(); default: break; } diff --git a/src/value.h b/src/value.h index bb04508e..069a3c46 100644 --- a/src/value.h +++ b/src/value.h @@ -404,11 +404,9 @@ public: } value_t abs() const; -#ifdef INTEGER_MATH - value_t round() const; - void in_place_round(); -#endif - value_t unround() const; + + value_t rounded() const; + value_t unrounded() const; value_t reduce() const { value_t temp(*this); diff --git a/test/unit/t_amount.cc b/test/unit/t_amount.cc index 3b199f5b..577a4aaf 100644 --- a/test/unit/t_amount.cc +++ b/test/unit/t_amount.cc @@ -213,6 +213,7 @@ void AmountTestCase::testCommodityConstructors() } #ifndef NOT_FOR_PYTHON + void AmountTestCase::testAssignment() { amount_t x0; @@ -318,6 +319,7 @@ void AmountTestCase::testCommodityAssignment() assertValid(x9); assertValid(x10); } + #endif // NOT_FOR_PYTHON void AmountTestCase::testEquality() @@ -423,8 +425,10 @@ void AmountTestCase::testComparisons() assertTrue(100L > x1); assertTrue(x1 < 100UL); assertTrue(100UL > x1); +#ifndef NOT_FOR_PYTHON assertTrue(x1 < 100.0); assertTrue(100.0 > x1); +#endif // NOT_FOR_PYTHON assertValid(x0); assertValid(x1); @@ -538,7 +542,9 @@ void AmountTestCase::testCommodityAddition() assertThrow(x1 + x4, amount_error); assertThrow(x1 + x5, amount_error); assertThrow(x1 + x6, amount_error); +#ifndef NOT_FOR_PYTHON assertThrow(x1 + 123.45, amount_error); +#endif // NOT_FOR_PYTHON assertThrow(x1 + 123L, amount_error); assertEqual(amount_t("DM 246.90"), x3 + x3); @@ -652,7 +658,9 @@ void AmountTestCase::testCommoditySubtraction() assertThrow(x1 - x4, amount_error); assertThrow(x1 - x5, amount_error); assertThrow(x1 - x6, amount_error); +#ifndef NOT_FOR_PYTHON assertThrow(x1 - 123.45, amount_error); +#endif // NOT_FOR_PYTHON assertThrow(x1 - 123L, amount_error); assertEqual(amount_t("DM 0.00"), x3 - x3); @@ -857,11 +865,7 @@ void AmountTestCase::testIntegerDivision() x1 /= amount_t(456L); assertEqual(string("0.269737"), x1.to_string()); x1 /= 456L; -#ifdef INTEGER_MATH - assertEqual(string("0.00059152850877193"), x1.to_string()); -#else assertEqual(string("0.000591528162511542"), x1.to_string()); -#endif amount_t x4("123456789123456789123456789"); amount_t y4("56"); @@ -901,13 +905,9 @@ void AmountTestCase::testFractionalDivision() x1 /= amount_t("456.456"); assertEqual(string("0.269736842105263"), x1.to_string()); x1 /= amount_t("456.456"); -#ifdef INTEGER_MATH - assertEqual(string("0.000590937225286255411255411255411255411"), x1.to_string()); -#else assertEqual(string("0.000590937225286255757169884601508201951"), x1.to_string()); -#endif x1 /= 456L; - assertEqual(string("0.000001295914967733016252753094858358016252192982456140350877192982456140350877192982"), x1.to_string()); + assertEqual(string("0.000001295914967733017011337466214297678193292890066687335298289595263924317558590360"), x1.to_string()); amount_t x4("1234567891234567.89123456789"); amount_t y4("56.789"); @@ -934,18 +934,18 @@ void AmountTestCase::testCommodityDivision() assertThrow(x1 / 0L, amount_error); assertEqual(amount_t("$0.00"), 0L / x1); assertEqual(x1, x1 / 1L); - assertEqual(string("$0.00812216"), (1L / x1).to_string()); + assertEqual(string("$0.00812216"), (1L / x1).to_fullstring()); assertEqual(- x1, x1 / -1L); - assertEqual(string("$-0.00812216"), (-1L / x1).to_string()); - assertEqual(string("$0.26973382"), (x1 / y1).to_string()); + assertEqual(string("$-0.00812216"), (-1L / x1).to_fullstring()); + assertEqual(string("$0.26973382"), (x1 / y1).to_fullstring()); assertEqual(string("$0.27"), (x1 / y1).to_string()); - assertEqual(string("$3.70735867"), (y1 / x1).to_string()); + assertEqual(string("$3.70735867"), (y1 / x1).to_fullstring()); assertEqual(string("$3.71"), (y1 / x1).to_string()); // Internal amounts retain their precision, even when being // converted to strings - assertEqual(string("$0.99727201"), (x1 / x2).to_string()); - assertEqual(string("$1.00273545321637426901"), (x2 / x1).to_string()); + assertEqual(string("$0.99727201"), (x1 / x2).to_fullstring()); + assertEqual(string("$1.00273545321637426901"), (x2 / x1).to_fullstring()); assertEqual(string("$1.00"), (x1 / x2).to_string()); assertEqual(string("$1.00273545321637426901"), (x2 / x1).to_string()); @@ -959,10 +959,10 @@ void AmountTestCase::testCommodityDivision() x1 /= amount_t("123.12"); assertEqual(string("$1.00"), x1.to_string()); x1 /= amount_t("123.12"); - assertEqual(string("$0.00812216"), x1.to_string()); + assertEqual(string("$0.00812216"), x1.to_fullstring()); assertEqual(string("$0.01"), x1.to_string()); x1 /= 123L; - assertEqual(string("$0.00006603"), x1.to_string()); + assertEqual(string("$0.00006603"), x1.to_fullstring()); assertEqual(string("$0.00"), x1.to_string()); amount_t x6(internalAmount("$237235987235987.98723987235978")); @@ -970,9 +970,9 @@ void AmountTestCase::testCommodityDivision() assertEqual(amount_t("$1"), x7 / x7); assertEqual(string("$0.0019216115121765559608381226612019501046413574469262"), - (x6 / x7).to_string()); + (x6 / x7).to_fullstring()); assertEqual(string("$520.39654928343335571379527154924040947271699678158689736256"), - (x7 / x6).to_string()); + (x7 / x6).to_fullstring()); assertValid(x1); assertValid(x2); @@ -1098,177 +1098,6 @@ void AmountTestCase::testCommodityAbs() assertValid(x2); } -#ifndef NOT_FOR_PYTHON -#ifdef INTEGER_MATH - -void AmountTestCase::testFractionalRound() -{ - amount_t x0; - amount_t x1("1234.567890"); - - assertThrow(x0.precision(), amount_error); - assertThrow(x0.round(), amount_error); - assertThrow(x0.round(2), amount_error); - assertThrow(x0.unround(), amount_error); - assertEqual(amount_t::precision_t(6), x1.precision()); - - amount_t x1b(x1.unround()); - - assertEqual(x1b.precision(), x1b.unround().precision()); - - amount_t y7(x1.round(7)); - amount_t y6(x1.round(6)); - amount_t y5(x1.round(5)); - amount_t y4(x1.round(4)); - amount_t y3(x1.round(3)); - amount_t y2(x1.round(2)); - amount_t y1(x1.round(1)); - amount_t y0(x1.round(0)); - - assertEqual(amount_t::precision_t(6), y7.precision()); - assertEqual(amount_t::precision_t(6), y6.precision()); - assertEqual(amount_t::precision_t(5), y5.precision()); - assertEqual(amount_t::precision_t(4), y4.precision()); - assertEqual(amount_t::precision_t(3), y3.precision()); - assertEqual(amount_t::precision_t(2), y2.precision()); - assertEqual(amount_t::precision_t(1), y1.precision()); - assertEqual(amount_t::precision_t(0), y0.precision()); - - assertEqual(amount_t("1234.56789"), y7); - assertEqual(amount_t("1234.56789"), y6); - assertEqual(amount_t("1234.56789"), y5); - assertEqual(amount_t("1234.5679"), y4); - assertEqual(amount_t("1234.568"), y3); - assertEqual(amount_t("1234.57"), y2); - assertEqual(amount_t("1234.6"), y1); - assertEqual(amount_t("1235"), y0); - - amount_t x2("9876.543210"); - - assertEqual(amount_t("9876.543210"), x2.round(6)); - assertEqual(amount_t("9876.54321"), x2.round(5)); - assertEqual(amount_t("9876.5432"), x2.round(4)); - assertEqual(amount_t("9876.543"), x2.round(3)); - assertEqual(amount_t("9876.54"), x2.round(2)); - assertEqual(amount_t("9876.5"), x2.round(1)); - assertEqual(amount_t("9877"), x2.round(0)); - - amount_t x3("-1234.567890"); - - assertEqual(amount_t("-1234.56789"), x3.round(6)); - assertEqual(amount_t("-1234.56789"), x3.round(5)); - assertEqual(amount_t("-1234.5679"), x3.round(4)); - assertEqual(amount_t("-1234.568"), x3.round(3)); - assertEqual(amount_t("-1234.57"), x3.round(2)); - assertEqual(amount_t("-1234.6"), x3.round(1)); - assertEqual(amount_t("-1235"), x3.round(0)); - - amount_t x4("-9876.543210"); - - assertEqual(amount_t("-9876.543210"), x4.round(6)); - assertEqual(amount_t("-9876.54321"), x4.round(5)); - assertEqual(amount_t("-9876.5432"), x4.round(4)); - assertEqual(amount_t("-9876.543"), x4.round(3)); - assertEqual(amount_t("-9876.54"), x4.round(2)); - assertEqual(amount_t("-9876.5"), x4.round(1)); - assertEqual(amount_t("-9877"), x4.round(0)); - - amount_t x5("0.0000000000000000000000000000000000001"); - - assertEqual(amount_t("0.0000000000000000000000000000000000001"), - x5.round(37)); - assertEqual(amount_t(0L), x5.round(36)); - - assertValid(x1); - assertValid(x2); - assertValid(x3); - assertValid(x4); - assertValid(x5); -} - -void AmountTestCase::testCommodityRound() -{ - amount_t x1(internalAmount("$1234.567890")); - - assertEqual(internalAmount("$1234.56789"), x1.round(6)); - assertEqual(internalAmount("$1234.56789"), x1.round(5)); - assertEqual(internalAmount("$1234.5679"), x1.round(4)); - assertEqual(internalAmount("$1234.568"), x1.round(3)); - assertEqual(amount_t("$1234.57"), x1.round(2)); - assertEqual(amount_t("$1234.6"), x1.round(1)); - assertEqual(amount_t("$1235"), x1.round(0)); - - amount_t x2(internalAmount("$9876.543210")); - - assertEqual(internalAmount("$9876.543210"), x2.round(6)); - assertEqual(internalAmount("$9876.54321"), x2.round(5)); - assertEqual(internalAmount("$9876.5432"), x2.round(4)); - assertEqual(internalAmount("$9876.543"), x2.round(3)); - assertEqual(amount_t("$9876.54"), x2.round(2)); - assertEqual(amount_t("$9876.5"), x2.round(1)); - assertEqual(amount_t("$9877"), x2.round(0)); - - amount_t x3(internalAmount("$-1234.567890")); - - assertEqual(internalAmount("$-1234.56789"), x3.round(6)); - assertEqual(internalAmount("$-1234.56789"), x3.round(5)); - assertEqual(internalAmount("$-1234.5679"), x3.round(4)); - assertEqual(internalAmount("$-1234.568"), x3.round(3)); - assertEqual(amount_t("$-1234.57"), x3.round(2)); - assertEqual(amount_t("$-1234.6"), x3.round(1)); - assertEqual(amount_t("$-1235"), x3.round(0)); - - amount_t x4(internalAmount("$-9876.543210")); - - assertEqual(internalAmount("$-9876.543210"), x4.round(6)); - assertEqual(internalAmount("$-9876.54321"), x4.round(5)); - assertEqual(internalAmount("$-9876.5432"), x4.round(4)); - assertEqual(internalAmount("$-9876.543"), x4.round(3)); - assertEqual(amount_t("$-9876.54"), x4.round(2)); - assertEqual(amount_t("$-9876.5"), x4.round(1)); - assertEqual(amount_t("$-9877"), x4.round(0)); - - amount_t x5("$123.45"); - - x5 *= amount_t("100.12"); - - assertEqual(internalAmount("$12359.814"), x5); - assertEqual(string("$12359.81"), x5.to_string()); - assertEqual(string("$12359.814"), x5.to_fullstring()); - assertEqual(string("$12359.814"), x5.unround().to_string()); - - assertValid(x1); - assertValid(x2); - assertValid(x3); - assertValid(x4); - assertValid(x5); -} - -void AmountTestCase::testCommodityDisplayRound() -{ - amount_t x1("$0.85"); - amount_t x2("$0.1"); - - x1 *= amount_t("0.19"); - - assertNotEqual(amount_t("$0.16"), x1); - assertEqual(internalAmount("$0.1615"), x1); - assertEqual(string("$0.16"), x1.to_string()); - - assertEqual(amount_t("$0.10"), x2); - assertNotEqual(internalAmount("$0.101"), x2); - assertEqual(string("$0.10"), x2.to_string()); - - x1 *= 7L; - - assertNotEqual(amount_t("$1.13"), x1); - assertEqual(internalAmount("$1.1305"), x1); - assertEqual(string("$1.13"), x1.to_string()); -} - -#endif // INTEGER_MATH -#endif - void AmountTestCase::testReduction() { amount_t x0; @@ -1411,10 +1240,7 @@ void AmountTestCase::testFractionalConversion() amount_t x1("1234.56"); amount_t x2("1234.5683787634678348734"); - assertThrow(x1.to_long(), amount_error); // loses precision - assertThrow(x2.to_double(), amount_error); // loses precision - assertFalse(x2.fits_in_double()); - assertEqual(1234L, x1.to_long(true)); + assertEqual(1235L, x1.to_long()); assertEqual(1234.56, x1.to_double()); assertEqual(string("1234.56"), x1.to_string()); assertEqual(string("1234.56"), x1.quantity_string()); @@ -1426,8 +1252,7 @@ void AmountTestCase::testCommodityConversion() { amount_t x1("$1234.56"); - assertThrow(x1.to_long(), amount_error); // loses precision - assertEqual(1234L, x1.to_long(true)); + assertEqual(1235L, x1.to_long()); assertEqual(1234.56, x1.to_double()); assertEqual(string("$1234.56"), x1.to_string()); assertEqual(string("1234.56"), x1.quantity_string()); @@ -1436,6 +1261,7 @@ void AmountTestCase::testCommodityConversion() } #ifndef NOT_FOR_PYTHON + void AmountTestCase::testPrinting() { amount_t x0; @@ -1579,4 +1405,5 @@ void AmountTestCase::testXmlSerialization() assertEqual(std::string("<amount>\n <commodity flags=\"PT\">\n <symbol>$</symbol>\n </commodity>\n <quantity>8192.34</quantity>\n</amount>\n"), storage.str()); } + #endif // NOT_FOR_PYTHON diff --git a/test/unit/t_amount.h b/test/unit/t_amount.h index 92bbe9b8..a3727c61 100644 --- a/test/unit/t_amount.h +++ b/test/unit/t_amount.h @@ -32,11 +32,6 @@ class AmountTestCase : public CPPUNIT_NS::TestCase CPPUNIT_TEST(testCommodityNegation); CPPUNIT_TEST(testAbs); CPPUNIT_TEST(testCommodityAbs); -#ifdef INTEGER_MATH - CPPUNIT_TEST(testFractionalRound); - CPPUNIT_TEST(testCommodityRound); - CPPUNIT_TEST(testCommodityDisplayRound); -#endif CPPUNIT_TEST(testReduction); CPPUNIT_TEST(testSign); CPPUNIT_TEST(testCommoditySign); diff --git a/test/unit/t_commodity.cc b/test/unit/t_commodity.cc index 81538e76..9818c863 100644 --- a/test/unit/t_commodity.cc +++ b/test/unit/t_commodity.cc @@ -75,22 +75,27 @@ void CommodityTestCase::testPriceHistory() amt = x1.value(current_time); assertTrue(amt); - assertEqual(amount_t("$2124.12"), *amt); + assertEqual(string("$2124.12"), amt->to_string()); +#ifdef INTEGER_MATH + assertEqual(string("$2124.12"), amt->to_fullstring()); +#else + assertEqual(string("$2124.1220"), amt->to_fullstring()); +#endif amt = x1.value(current_time, euro); assertTrue(amt); - assertEqual(amount_t("EUR 1366.87"), *amt); + assertEqual(string("EUR 1366.87"), amt->rounded().to_string()); // Add a newer Euro pricing aapl.add_price(jan17_07, amount_t("EUR 23.00")); amt = x1.value(current_time, euro); assertTrue(amt); - assertEqual(amount_t("EUR 2302.30"), *amt); + assertEqual(string("EUR 2302.30"), amt->to_string()); amt = x1.value(current_time, cad); assertTrue(amt); - assertEqual(amount_t("CAD 3223.22"), *amt); + assertEqual(string("CAD 3223.22"), amt->to_string()); #endif // NOT_FOR_PYTHON assertValid(x1); |