diff options
author | John Wiegley <johnw@newartisans.com> | 2009-11-11 03:39:53 -0500 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-11-11 03:39:53 -0500 |
commit | afe87280e091d4f094f068c5f21aecccd2d1831b (patch) | |
tree | 4be3e5c9bbcc9b450a6c0eea3f6b959daab22757 /src | |
parent | 4a4ff9d4b21e7ed94524314ca496bd17c84fc4ed (diff) | |
download | fork-ledger-afe87280e091d4f094f068c5f21aecccd2d1831b.tar.gz fork-ledger-afe87280e091d4f094f068c5f21aecccd2d1831b.tar.bz2 fork-ledger-afe87280e091d4f094f068c5f21aecccd2d1831b.zip |
Added floored() and in_place_floor() methods
Diffstat (limited to 'src')
-rw-r--r-- | src/amount.cc | 199 | ||||
-rw-r--r-- | src/amount.h | 9 | ||||
-rw-r--r-- | src/balance.h | 12 | ||||
-rw-r--r-- | src/py_amount.cc | 4 | ||||
-rw-r--r-- | src/py_balance.cc | 4 | ||||
-rw-r--r-- | src/py_value.cc | 2 | ||||
-rw-r--r-- | src/value.cc | 25 | ||||
-rw-r--r-- | src/value.h | 7 |
8 files changed, 169 insertions, 93 deletions
diff --git a/src/amount.cc b/src/amount.cc index 28fa9eaf..f8406505 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -114,6 +114,99 @@ shared_ptr<commodity_pool_t> amount_t::current_pool; bool amount_t::is_initialized = false; +namespace { + void stream_out_mpq(std::ostream& out, + mpq_t quant, + amount_t::precision_t prec, + int zeros_prec = -1, + const optional<commodity_t&>& comm = none) + { + char * buf = NULL; + try { + IF_DEBUG("amount.convert") { + char * tbuf = mpq_get_str(NULL, 10, quant); + DEBUG("amount.convert", "Rational to convert = " << tbuf); + std::free(tbuf); + } + + // Convert the rational number to a floating-point, extending the + // floating-point to a large enough size to get a precise answer. + const std::size_t bits = (mpz_sizeinbase(mpq_numref(quant), 2) + + mpz_sizeinbase(mpq_denref(quant), 2)); + mpfr_set_prec(tempfb, bits + amount_t::extend_by_digits*8); + mpfr_set_q(tempfb, quant, GMP_RNDN); + + mpfr_asprintf(&buf, "%.*Rf", prec, tempfb); + DEBUG("amount.convert", + "mpfr_print = " << buf << " (precision " << prec << ")"); + + if (zeros_prec >= 0) { + string::size_type index = std::strlen(buf); + string::size_type point = 0; + for (string::size_type i = 0; i < index; i++) { + if (buf[i] == '.') { + point = i; + break; + } + } + if (point > 0) { + while (--index >= (point + 1 + zeros_prec) && buf[index] == '0') + buf[index] = '\0'; + if (index >= (point + zeros_prec) && buf[index] == '.') + buf[index] = '\0'; + } + } + + if (comm) { + int integer_digits = 0; + if (comm && comm->has_flags(COMMODITY_STYLE_THOUSANDS)) { + // Count the number of integer digits + for (const char * p = buf; *p; p++) { + if (*p == '.') + break; + else if (*p != '-') + integer_digits++; + } + } + + for (const char * p = buf; *p; p++) { + if (*p == '.') { + if (commodity_t::european_by_default || + (comm && comm->has_flags(COMMODITY_STYLE_EUROPEAN))) + out << ','; + else + out << *p; + assert(integer_digits <= 3); + } + else if (*p == '-') { + out << *p; + } + else { + out << *p; + + if (integer_digits > 3 && --integer_digits % 3 == 0) { + if (commodity_t::european_by_default || + (comm && comm->has_flags(COMMODITY_STYLE_EUROPEAN))) + out << '.'; + else + out << ','; + } + } + } + } else { + out << buf; + } + } + catch (...) { + if (buf != NULL) + mpfr_free_str(buf); + throw; + } + if (buf != NULL) + mpfr_free_str(buf); + } +} + void amount_t::initialize(shared_ptr<commodity_pool_t> pool) { if (! is_initialized) { @@ -498,6 +591,19 @@ void amount_t::in_place_round() set_keep_precision(false); } +void amount_t::in_place_floor() +{ + if (! quantity) + throw_(amount_error, _("Cannot floor an uninitialized amount")); + + _dup(); + + std::ostringstream out; + stream_out_mpq(out, MP(quantity), 0); + + mpq_set_str(MP(quantity), out.str().c_str(), 10); +} + void amount_t::in_place_unround() { if (! quantity) @@ -612,99 +718,6 @@ int amount_t::sign() const return mpq_sgn(MP(quantity)); } -namespace { - void stream_out_mpq(std::ostream& out, - mpq_t quant, - amount_t::precision_t prec, - int zeros_prec = -1, - const optional<commodity_t&>& comm = none) - { - char * buf = NULL; - try { - IF_DEBUG("amount.convert") { - char * tbuf = mpq_get_str(NULL, 10, quant); - DEBUG("amount.convert", "Rational to convert = " << tbuf); - std::free(tbuf); - } - - // Convert the rational number to a floating-point, extending the - // floating-point to a large enough size to get a precise answer. - const std::size_t bits = (mpz_sizeinbase(mpq_numref(quant), 2) + - mpz_sizeinbase(mpq_denref(quant), 2)); - mpfr_set_prec(tempfb, bits + amount_t::extend_by_digits*8); - mpfr_set_q(tempfb, quant, GMP_RNDN); - - mpfr_asprintf(&buf, "%.*Rf", prec, tempfb); - DEBUG("amount.convert", - "mpfr_print = " << buf << " (precision " << prec << ")"); - - if (zeros_prec >= 0) { - string::size_type index = std::strlen(buf); - string::size_type point = 0; - for (string::size_type i = 0; i < index; i++) { - if (buf[i] == '.') { - point = i; - break; - } - } - if (point > 0) { - while (--index >= (point + 1 + zeros_prec) && buf[index] == '0') - buf[index] = '\0'; - if (index >= (point + zeros_prec) && buf[index] == '.') - buf[index] = '\0'; - } - } - - if (comm) { - int integer_digits = 0; - if (comm && comm->has_flags(COMMODITY_STYLE_THOUSANDS)) { - // Count the number of integer digits - for (const char * p = buf; *p; p++) { - if (*p == '.') - break; - else if (*p != '-') - integer_digits++; - } - } - - for (const char * p = buf; *p; p++) { - if (*p == '.') { - if (commodity_t::european_by_default || - (comm && comm->has_flags(COMMODITY_STYLE_EUROPEAN))) - out << ','; - else - out << *p; - assert(integer_digits <= 3); - } - else if (*p == '-') { - out << *p; - } - else { - out << *p; - - if (integer_digits > 3 && --integer_digits % 3 == 0) { - if (commodity_t::european_by_default || - (comm && comm->has_flags(COMMODITY_STYLE_EUROPEAN))) - out << '.'; - else - out << ','; - } - } - } - } else { - out << buf; - } - } - catch (...) { - if (buf != NULL) - mpfr_free_str(buf); - throw; - } - if (buf != NULL) - mpfr_free_str(buf); - } -} - bool amount_t::is_zero() const { if (! quantity) diff --git a/src/amount.h b/src/amount.h index 505e2ea7..c75370e3 100644 --- a/src/amount.h +++ b/src/amount.h @@ -354,6 +354,15 @@ public: *this = amount_t(to_string()); } + /** Yields an amount which has lost all of its extra precision, beyond what + the display precision of the commodity would have printed. */ + amount_t floored() const { + amount_t temp(*this); + temp.in_place_floor(); + return temp; + } + void in_place_floor(); + /** Yields an amount whose display precision is never truncated, even though its commodity normally displays only rounded values. */ amount_t unrounded() const { diff --git a/src/balance.h b/src/balance.h index 81a7ff13..8a40dea9 100644 --- a/src/balance.h +++ b/src/balance.h @@ -339,6 +339,18 @@ public: *this = temp; } + balance_t floored() const { + balance_t temp(*this); + temp.in_place_floor(); + return temp; + } + void in_place_floor() { + balance_t temp; + foreach (const amounts_map::value_type& pair, amounts) + temp += pair.second.floored(); + *this = temp; + } + balance_t unrounded() const { balance_t temp(*this); temp.in_place_unround(); diff --git a/src/py_amount.cc b/src/py_amount.cc index 83f5dd29..b44f3716 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -220,6 +220,10 @@ internal precision.")) .def("in_place_truncate", &amount_t::in_place_truncate, return_internal_reference<>()) + .def("floored", &amount_t::floored) + .def("in_place_floor", &amount_t::in_place_floor, + return_internal_reference<>()) + .def("unrounded", &amount_t::unrounded) .def("in_place_unround", &amount_t::in_place_unround, return_internal_reference<>()) diff --git a/src/py_balance.cc b/src/py_balance.cc index 73049c99..23a2ff73 100644 --- a/src/py_balance.cc +++ b/src/py_balance.cc @@ -176,6 +176,10 @@ void export_balance() .def("in_place_truncate", &balance_t::in_place_truncate, return_internal_reference<>()) + .def("floored", &balance_t::floored) + .def("in_place_floor", &balance_t::in_place_floor, + return_internal_reference<>()) + .def("unrounded", &balance_t::unrounded) .def("in_place_unround", &balance_t::in_place_unround, return_internal_reference<>()) diff --git a/src/py_value.cc b/src/py_value.cc index c8e4de72..e94e74c1 100644 --- a/src/py_value.cc +++ b/src/py_value.cc @@ -234,6 +234,8 @@ void export_value() .def("in_place_round", &value_t::in_place_round) .def("truncated", &value_t::truncated) .def("in_place_truncate", &value_t::in_place_truncate) + .def("floored", &value_t::floored) + .def("in_place_floor", &value_t::in_place_floor) .def("unrounded", &value_t::unrounded) .def("in_place_unround", &value_t::in_place_unround) .def("reduced", &value_t::reduced) diff --git a/src/value.cc b/src/value.cc index 021bf957..ae86eb7c 100644 --- a/src/value.cc +++ b/src/value.cc @@ -1439,6 +1439,31 @@ void value_t::in_place_truncate() throw_(value_error, _("Cannot truncate %1") << label()); } +void value_t::in_place_floor() +{ + switch (type()) { + case INTEGER: + return; + case AMOUNT: + as_amount_lval().in_place_floor(); + return; + case BALANCE: + as_balance_lval().in_place_floor(); + return; + case SEQUENCE: { + value_t temp; + foreach (const value_t& value, as_sequence()) + temp.push_back(value.floored()); + *this = temp; + return; + } + default: + break; + } + + throw_(value_error, _("Cannot floor %1") << label()); +} + void value_t::in_place_unround() { switch (type()) { diff --git a/src/value.h b/src/value.h index 96a3078a..2a420cd3 100644 --- a/src/value.h +++ b/src/value.h @@ -440,6 +440,13 @@ public: } void in_place_truncate(); + value_t floored() const { + value_t temp(*this); + temp.in_place_floor(); + return temp; + } + void in_place_floor(); + value_t unrounded() const { value_t temp(*this); temp.in_place_unround(); |