[ruby/bigdecimal] Fix the result precision of BigDecimal#divmod
https://github.com/ruby/bigdecimal/commit/a32f6cb9e2
This commit is contained in:
parent
680a4ebb3c
commit
a1d9fbef05
@ -1618,7 +1618,8 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
|
|||||||
/* For c = self.div(r): with round operation */
|
/* For c = self.div(r): with round operation */
|
||||||
{
|
{
|
||||||
ENTER(5);
|
ENTER(5);
|
||||||
Real *a, *b;
|
Real *a, *b, *d;
|
||||||
|
ssize_t a_prec, b_prec;
|
||||||
size_t mx;
|
size_t mx;
|
||||||
|
|
||||||
TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
|
TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
|
||||||
@ -1644,18 +1645,27 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
|
|||||||
|
|
||||||
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
||||||
SAVE(b);
|
SAVE(b);
|
||||||
|
|
||||||
*div = b;
|
*div = b;
|
||||||
|
|
||||||
mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
|
mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
|
||||||
mx *= BASE_FIG;
|
mx *= BASE_FIG;
|
||||||
|
|
||||||
|
BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
|
||||||
|
BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
|
||||||
|
mx = (a_prec > b_prec) ? a_prec : b_prec;
|
||||||
|
|
||||||
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
||||||
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
||||||
|
|
||||||
GUARD_OBJ((*c), VpCreateRbObject(mx + 2*BASE_FIG, "#0", true));
|
GUARD_OBJ((*c), VpCreateRbObject(mx + 2*BASE_FIG, "#0", true));
|
||||||
GUARD_OBJ((*res), VpCreateRbObject(mx*2 + 2*BASE_FIG, "#0", true));
|
GUARD_OBJ((*res), VpCreateRbObject(mx*2 + 2*BASE_FIG, "#0", true));
|
||||||
VpDivd(*c, *res, a, b);
|
VpDivd(*c, *res, a, b);
|
||||||
|
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
|
||||||
|
|
||||||
/* call-seq:
|
/* call-seq:
|
||||||
* a / b -> bigdecimal
|
* a / b -> bigdecimal
|
||||||
*
|
*
|
||||||
@ -1736,6 +1746,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|||||||
ENTER(8);
|
ENTER(8);
|
||||||
Real *c=NULL, *d=NULL, *res=NULL;
|
Real *c=NULL, *d=NULL, *res=NULL;
|
||||||
Real *a, *b;
|
Real *a, *b;
|
||||||
|
ssize_t a_prec, b_prec;
|
||||||
size_t mx;
|
size_t mx;
|
||||||
|
|
||||||
TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
|
TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
|
||||||
@ -1793,8 +1804,10 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|||||||
return Qtrue;
|
return Qtrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
|
BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
|
||||||
mx *= BASE_FIG;
|
BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
|
||||||
|
|
||||||
|
mx = (a_prec > b_prec) ? a_prec : b_prec;
|
||||||
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
||||||
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
||||||
|
|
||||||
|
@ -1047,11 +1047,13 @@ class TestBigDecimal < Test::Unit::TestCase
|
|||||||
a = BigDecimal('2e55')
|
a = BigDecimal('2e55')
|
||||||
b = BigDecimal('1.23456789e10')
|
b = BigDecimal('1.23456789e10')
|
||||||
q, r = a.divmod(b)
|
q, r = a.divmod(b)
|
||||||
assert_equal((a/b), q)
|
assert_equal((a/b).round(0, :down), q)
|
||||||
|
assert_equal((a - q*b), r)
|
||||||
|
|
||||||
b = BigDecimal('-1.23456789e10')
|
b = BigDecimal('-1.23456789e10')
|
||||||
q, r = a.divmod(b)
|
q, r = a.divmod(b)
|
||||||
assert_equal((a/b), q)
|
assert_equal((a/b).round(0, :down) - 1, q)
|
||||||
|
assert_equal((a - q*b), r)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_divmod_error
|
def test_divmod_error
|
||||||
|
Loading…
x
Reference in New Issue
Block a user