Skip to content

Commit bf22f51

Browse files
authored
Remove BigDecimal_divremain(which has a bug) and use BigDecimal_DoDivmod instead (#351)
1 parent eaa9d8a commit bf22f51

File tree

2 files changed

+16
-64
lines changed

2 files changed

+16
-64
lines changed

ext/bigdecimal/bigdecimal.c

Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,7 +1823,7 @@ BigDecimal_mult(VALUE self, VALUE r)
18231823
return VpCheckGetValue(c);
18241824
}
18251825

1826-
static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
1826+
static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod, bool truncate);
18271827

18281828
/* call-seq:
18291829
* a / b -> bigdecimal
@@ -1893,9 +1893,10 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
18931893
/*
18941894
* %: mod = a%b = a - (a.to_f/b).floor * b
18951895
* div = (a.to_f/b).floor
1896+
* In truncate mode, use truncate instead of floor.
18961897
*/
18971898
static VALUE
1898-
BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1899+
BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod, bool truncate)
18991900
{
19001901
ENTER(8);
19011902
Real *c=NULL, *d=NULL, *res=NULL;
@@ -1978,7 +1979,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
19781979
VpMult(res, d, b);
19791980
VpAddSub(c, a, res, -1);
19801981

1981-
if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1982+
if (!truncate && !VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
19821983
/* result adjustment for negative case */
19831984
res = rbd_reallocate_struct(res, d->MaxPrec);
19841985
res->MaxPrec = d->MaxPrec;
@@ -2017,66 +2018,13 @@ BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
20172018
ENTER(3);
20182019
Real *div = NULL, *mod = NULL;
20192020

2020-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2021-
SAVE(div); SAVE(mod);
2021+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
2022+
SAVE(div); SAVE(mod);
20222023
return VpCheckGetValue(mod);
20232024
}
20242025
return DoSomeOne(self, r, '%');
20252026
}
20262027

2027-
static VALUE
2028-
BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2029-
{
2030-
ENTER(10);
2031-
size_t mx;
2032-
Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
2033-
Real *f = NULL;
2034-
2035-
GUARD_OBJ(a, GetVpValue(self, 1));
2036-
if (RB_TYPE_P(r, T_FLOAT)) {
2037-
b = GetVpValueWithPrec(r, 0, 1);
2038-
}
2039-
else if (RB_TYPE_P(r, T_RATIONAL)) {
2040-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
2041-
}
2042-
else {
2043-
b = GetVpValue(r, 0);
2044-
}
2045-
2046-
if (!b) return Qfalse;
2047-
SAVE(b);
2048-
2049-
if (VpIsPosInf(b) || VpIsNegInf(b)) {
2050-
GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
2051-
VpSetZero(*dv, 1);
2052-
*rv = a;
2053-
return Qtrue;
2054-
}
2055-
2056-
mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
2057-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2058-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2059-
GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2060-
GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2061-
2062-
VpDivd(c, res, a, b);
2063-
2064-
mx = c->Prec *(VpBaseFig() + 1);
2065-
2066-
GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2067-
GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
2068-
2069-
VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
2070-
2071-
VpFrac(f, c);
2072-
VpMult(rr, f, b);
2073-
VpAddSub(ff, res, rr, 1);
2074-
2075-
*dv = d;
2076-
*rv = ff;
2077-
return Qtrue;
2078-
}
2079-
20802028
/* call-seq:
20812029
* remainder(value)
20822030
*
@@ -2087,9 +2035,12 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
20872035
static VALUE
20882036
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
20892037
{
2090-
Real *d, *rv = 0;
2091-
if (BigDecimal_divremain(self, r, &d, &rv)) {
2092-
return VpCheckGetValue(rv);
2038+
ENTER(3);
2039+
Real *div = NULL, *mod = NULL;
2040+
2041+
if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
2042+
SAVE(div); SAVE(mod);
2043+
return VpCheckGetValue(mod);
20932044
}
20942045
return DoSomeOne(self, r, rb_intern("remainder"));
20952046
}
@@ -2122,7 +2073,7 @@ BigDecimal_divmod(VALUE self, VALUE r)
21222073
ENTER(5);
21232074
Real *div = NULL, *mod = NULL;
21242075

2125-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2076+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
21262077
SAVE(div); SAVE(mod);
21272078
return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
21282079
}
@@ -2145,7 +2096,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
21452096
if (NIL_P(n)) { /* div in Float sense */
21462097
Real *div = NULL;
21472098
Real *mod;
2148-
if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
2099+
if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
21492100
return BigDecimal_to_i(VpCheckGetValue(div));
21502101
}
21512102
return DoSomeOne(self, b, rb_intern("div"));

test/bigdecimal/test_bigdecimal.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,7 @@ def test_remainder
10791079
assert_equal(-1, (-x).remainder(3))
10801080
assert_equal(1, x.remainder(-3))
10811081
assert_equal(-1, (-x).remainder(-3))
1082+
assert_equal(BigDecimal("1e-10"), BigDecimal("1e10").remainder(BigDecimal("3e-10")))
10821083
end
10831084

10841085
def test_remainder_with_float
@@ -1091,7 +1092,7 @@ def test_remainder_with_rational
10911092

10921093
def test_remainder_coerce
10931094
o = Object.new
1094-
def o.coerce(x); [x, BigDecimal("3")]; end
1095+
def o.coerce(x); [x, BigDecimal("-3")]; end
10951096
assert_equal(BigDecimal("1.1"), BigDecimal("7.1").remainder(o))
10961097
end
10971098

0 commit comments

Comments
 (0)