Skip to content

Commit 0906cd7

Browse files
committed
numeric.c: fix rounding function issues with big numbers
- int_ceil - int_floor - int_round - int_truncate
1 parent 8d1192f commit 0906cd7

File tree

1 file changed

+62
-22
lines changed

1 file changed

+62
-22
lines changed

src/numeric.c

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,16 +1611,26 @@ int_ceil(mrb_state *mrb, mrb_value x)
16111611
if (mrb_nil_p(f)) return x;
16121612
#ifdef MRB_USE_BIGINT
16131613
if (mrb_bigint_p(x)) {
1614-
return mrb_bint_add(mrb, x, mrb_bint_sub(mrb, x, mrb_bint_mod(mrb, x, f)));
1614+
x = mrb_bint_add_d(mrb, x, f);
1615+
return mrb_bint_sub(mrb, x, mrb_bint_mod(mrb, x, f));
16151616
}
16161617
#endif
16171618
mrb_int a = mrb_integer(x);
16181619
mrb_int b = mrb_integer(f);
1620+
mrb_int c = a % b;
16191621
int neg = a < 0;
1620-
if (neg) a = -a;
1621-
else a += b - 1;
1622-
a = a / b * b;
1623-
if (neg) a = -a;
1622+
a -= c;
1623+
if (!neg) {
1624+
if (mrb_int_add_overflow(a, b, &c)) {
1625+
#ifdef MRB_USE_BIGINT
1626+
x = mrb_bint_new_int(mrb, a);
1627+
return mrb_bint_add(mrb, x, f);
1628+
#else
1629+
mrb_int_overflow(mrb, "ceil");
1630+
#endif
1631+
}
1632+
a = c;
1633+
}
16241634
return mrb_int_value(mrb, a);
16251635
}
16261636

@@ -1648,10 +1658,20 @@ int_floor(mrb_state *mrb, mrb_value x)
16481658
#endif
16491659
mrb_int a = mrb_integer(x);
16501660
mrb_int b = mrb_integer(f);
1661+
mrb_int c = a % b;
16511662
int neg = a < 0;
1652-
if (neg) a = -a + b - 1;
1653-
a = a / b * b;
1654-
if (neg) a = -a;
1663+
a -= c;
1664+
if (neg) {
1665+
if (mrb_int_sub_overflow(a, b, &c)) {
1666+
#ifdef MRB_USE_BIGINT
1667+
x = mrb_bint_new_int(mrb, a);
1668+
return mrb_bint_sub(mrb, x, f);
1669+
#else
1670+
mrb_int_overflow(mrb, "floor");
1671+
#endif
1672+
}
1673+
a = c;
1674+
}
16551675
return mrb_int_value(mrb, a);
16561676
}
16571677

@@ -1677,7 +1697,7 @@ int_round(mrb_state *mrb, mrb_value x)
16771697
mrb_value r = mrb_bint_mod(mrb, x, f);
16781698
mrb_value n = mrb_bint_sub(mrb, x, r);
16791699
mrb_value h = mrb_bigint_p(f) ? mrb_bint_rshift(mrb, f, 1) : mrb_int_value(mrb, mrb_integer(f)>>1);
1680-
mrb_int cmp = mrb_bigint_p(r) ? mrb_bint_cmp(mrb, r, h) : (mrb_integer(r) - mrb_integer(h));
1700+
mrb_int cmp = mrb_bigint_p(r) ? mrb_bint_cmp(mrb, r, h) : (mrb_bigint_p(h) ? -mrb_bint_cmp(mrb, h, r) : (mrb_integer(r)-mrb_integer(h)));
16811701
if ((cmp > 0) || (cmp == 0 && mrb_bint_cmp(mrb, x, mrb_fixnum_value(0)) > 0)) {
16821702
n = mrb_as_bint(mrb, n);
16831703
n = mrb_bint_add(mrb, n, f);
@@ -1687,10 +1707,35 @@ int_round(mrb_state *mrb, mrb_value x)
16871707
#endif
16881708
mrb_int a = mrb_integer(x);
16891709
mrb_int b = mrb_integer(f);
1690-
int neg = a < 0;
1691-
if (neg) a = -a;
1692-
a = (a + b / 2) / b * b;
1693-
if (neg) a = -a;
1710+
mrb_int c = a % b;
1711+
a -= c;
1712+
if (c < 0) {
1713+
c = -c;
1714+
if (b/2 < c) {
1715+
if (mrb_int_sub_overflow(a, b, &c)) {
1716+
#ifdef MRB_USE_BIGINT
1717+
x = mrb_bint_new_int(mrb, a);
1718+
return mrb_bint_sub(mrb, x, f);
1719+
#else
1720+
mrb_int_overflow(mrb, "round");
1721+
#endif
1722+
}
1723+
}
1724+
a = c;
1725+
}
1726+
else {
1727+
if (b/2 < c) {
1728+
if (mrb_int_add_overflow(a, b, &c)) {
1729+
#ifdef MRB_USE_BIGINT
1730+
x = mrb_bint_new_int(mrb, a);
1731+
return mrb_bint_add(mrb, x, f);
1732+
#else
1733+
mrb_int_overflow(mrb, "round");
1734+
#endif
1735+
}
1736+
}
1737+
a = c;
1738+
}
16941739
return mrb_int_value(mrb, a);
16951740
}
16961741

@@ -1714,21 +1759,16 @@ int_truncate(mrb_state *mrb, mrb_value x)
17141759
#ifdef MRB_USE_BIGINT
17151760
if (mrb_bigint_p(x)) {
17161761
mrb_value m = mrb_bint_mod(mrb, x, f);
1762+
x = mrb_bint_sub_d(mrb, x, m);
17171763
if (mrb_bint_cmp(mrb, x, mrb_fixnum_value(0)) < 0) {
1718-
return mrb_bint_add(mrb, x, mrb_bint_sub(mrb, x, m));
1719-
}
1720-
else {
1721-
return mrb_bint_sub(mrb, x, m);
1764+
return mrb_bint_add(mrb, x, f);
17221765
}
1766+
return x;
17231767
}
17241768
#endif
17251769
mrb_int a = mrb_integer(x);
17261770
mrb_int b = mrb_integer(f);
1727-
int neg = a < 0;
1728-
if (neg) a = -a;
1729-
a = a / b * b;
1730-
if (neg) a = -a;
1731-
return mrb_int_value(mrb, a);
1771+
return mrb_int_value(mrb, a - (a % b));
17321772
}
17331773

17341774
/* 15.2.8.3.23 */

0 commit comments

Comments
 (0)