-
Notifications
You must be signed in to change notification settings - Fork 78
Integrate BigDecimal_div and BigDecimal_div2 #329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ecified Fixes exponential precision grouth. `max(divisor_prec, dividend_prec) + extra_prec` is enough for division precision.
GUARD_OBJ(cv, NewZeroWrapLimited(1, ix + 3 * VpBaseFig())); | ||
|
||
mx = bv->Prec + cv->MaxPrec - 1; | ||
if (mx <= av->Prec) mx = av->Prec + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct allocation size calculation of res.
VpDivd requires word_a < word_r && word_b + word_c - 2 < word_r
ssize_t a_prec, b_prec; | ||
BigDecimal_count_precision_and_scale(av->obj, &a_prec, NULL); | ||
BigDecimal_count_precision_and_scale(bv->obj, &b_prec, NULL); | ||
ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
max(a_prec, b_prec) + extra_prec
is enough. Fixes exponential precision growth.
@@ -6164,7 +6119,7 @@ VpDivd(Real *c, Real *r, Real *a, Real *b) | |||
word_c = c->MaxPrec; | |||
word_r = r->MaxPrec; | |||
|
|||
if (word_a >= word_r) goto space_error; | |||
if (word_a >= word_r || word_b + word_c - 2 >= word_r) goto space_error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two more goto space_error
in this function.
One is on L6218
ind_r = ind_c + ind_b;
if (ind_r >= word_r) goto space_error;
And another in L6253
ind_r = b->Prec + ind_c - 1; // L6242
ind_r = b->Prec + ind_c; // L6250 (ind_c + 1 < word_c is ensured in L6247)
if (ind_r >= word_r) goto space_error;
Both has the same requirement: (word_b-1) + (word_c-1) < word_r
@@ -510,10 +510,10 @@ def test_round_up | |||
|
|||
BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_HALF_DOWN) | |||
assert_operator(n4, :>, n4 / 9 * 9) | |||
assert_operator(n5, :>, n5 / 9 * 9) | |||
assert_operator(n5, :<, n5 / 9 * 9) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Half down rules are:
123.5 → 123 (half down)
123.50001 → 124 (round up because it's larger than half)
0.55550 → 0.555
0.55551 → 0.556
0.55555555.. → 0.556 (Because it's larger than half)
In master branch, rounding is inconsistent between a / b
and a.div(b, prec)
.
BigDecimal.mode(BigDecimal::ROUND_MODE, BigDecimal::ROUND_HALF_DOWN)
BigDecimal(5)/9
#=> 0.555555555555555555555555555555555555e0 (ends with 5)
BigDecimal(5).div(9, 36)
#=> 0.555555555555555555555555555555555556e0 (ends with 6)
Fixes #220, #222 and #272
BigDecimal_div and BigDecimal_div2 both have rounding problem (#272 and #328)
Integrating two division logic will make it easy to fix them.
Precision calculation for
a / b
anda.div(b, 0)
is improved. There is no exponential precision growth anymore.