Abstracted precision extension constant, and added a note that precision must

be handled differently, since paying attention to places after the decimal is
not enough.
This commit is contained in:
John Wiegley 2008-11-23 19:15:32 -04:00
parent 7ce1c4e5a9
commit c172281858
2 changed files with 23 additions and 8 deletions

View file

@ -494,9 +494,10 @@ amount_t& amount_t::operator*=(const amount_t& amt)
if (has_commodity() && ! (quantity->has_flags(BIGINT_KEEP_PREC))) {
precision_t comm_prec = commodity().precision();
if (quantity->prec > comm_prec + 6U) {
mpz_round(MPZ(quantity), MPZ(quantity), quantity->prec, comm_prec + 6U);
quantity->prec = comm_prec + 6U;
if (quantity->prec > comm_prec + extend_by_digits) {
mpz_round(MPZ(quantity), MPZ(quantity), quantity->prec,
comm_prec + extend_by_digits);
quantity->prec = comm_prec + extend_by_digits;
}
}
@ -524,10 +525,17 @@ 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.
mpz_ui_pow_ui(divisor, 10, (2 * amt.quantity->prec) + quantity->prec + 7U);
// jww (2008-11-13): I need to consider the magnitude of the numerator
// of both numbers. For example, if I divide 10 by
// 100000000000000000000000000000000000, the result will be 0 because
// even extend_by_digits * 2 will not be enough digits of precision to
// retain the significance of the answer.
mpz_ui_pow_ui(divisor, 10,
(2 * amt.quantity->prec) + quantity->prec + extend_by_digits + 1U);
mpz_mul(MPZ(quantity), MPZ(quantity), divisor);
mpz_tdiv_q(MPZ(quantity), MPZ(quantity), MPZ(amt.quantity));
quantity->prec += amt.quantity->prec + quantity->prec + 7U;
quantity->prec += amt.quantity->prec + quantity->prec + extend_by_digits + 1U;
mpz_round(MPZ(quantity), MPZ(quantity), quantity->prec, quantity->prec - 1);
quantity->prec -= 1;
@ -542,9 +550,10 @@ amount_t& amount_t::operator/=(const amount_t& amt)
if (has_commodity() && ! (quantity->has_flags(BIGINT_KEEP_PREC))) {
precision_t comm_prec = commodity().precision();
if (quantity->prec > comm_prec + 6U) {
mpz_round(MPZ(quantity), MPZ(quantity), quantity->prec, comm_prec + 6U);
quantity->prec = comm_prec + 6U;
if (quantity->prec > comm_prec + extend_by_digits) {
mpz_round(MPZ(quantity), MPZ(quantity), quantity->prec,
comm_prec + extend_by_digits);
quantity->prec = comm_prec + extend_by_digits;
}
}

View file

@ -100,6 +100,12 @@ public:
*/
typedef uint_least16_t precision_t;
/**
* The number of places of precision by which values are extended to
* avoid losing precision during division and multiplication.
*/
static const unsigned int extend_by_digits = 8U;
/**
* The current_pool is a static variable indicating which commodity
* pool should be used.