summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2009-11-11 03:39:53 -0500
committerJohn Wiegley <johnw@newartisans.com>2009-11-11 03:39:53 -0500
commitafe87280e091d4f094f068c5f21aecccd2d1831b (patch)
tree4be3e5c9bbcc9b450a6c0eea3f6b959daab22757
parent4a4ff9d4b21e7ed94524314ca496bd17c84fc4ed (diff)
downloadfork-ledger-afe87280e091d4f094f068c5f21aecccd2d1831b.tar.gz
fork-ledger-afe87280e091d4f094f068c5f21aecccd2d1831b.tar.bz2
fork-ledger-afe87280e091d4f094f068c5f21aecccd2d1831b.zip
Added floored() and in_place_floor() methods
-rw-r--r--src/amount.cc199
-rw-r--r--src/amount.h9
-rw-r--r--src/balance.h12
-rw-r--r--src/py_amount.cc4
-rw-r--r--src/py_balance.cc4
-rw-r--r--src/py_value.cc2
-rw-r--r--src/value.cc25
-rw-r--r--src/value.h7
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();