summaryrefslogtreecommitdiff
path: root/numeric.c
diff options
context:
space:
mode:
authorPeter Zhu <[email protected]>2024-07-26 11:10:53 -0400
committerPeter Zhu <[email protected]>2024-07-30 08:21:28 -0400
commita7167d0ceecc8eea7bdf87e66be16d16b0f417e7 (patch)
tree8f4b9c2eca4750baa5ef7fe37139e07621235647 /numeric.c
parent3af2a7fbe12e11bac7b26bd991d3d02349f47295 (diff)
Fix ceil when ndigits is large
[Bug #20654] This commit fixes Integer#ceil and Float#ceil when the number is negative and ndigits is large such that 10**ndigits is a bignum. Previously, it would return 0 in such cases. However, this would cause unexpected behaviour such as: puts 1.ceil(-5) # => 100000 puts 1.ceil(-10) # => 10000000000 puts 1.ceil(-20) # => 0 This commit changes the last result so that it will return 100000000000000000000.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/11257
Diffstat (limited to 'numeric.c')
-rw-r--r--numeric.c19
1 files changed, 10 insertions, 9 deletions
diff --git a/numeric.c b/numeric.c
index 329067189b..3a19abea79 100644
--- a/numeric.c
+++ b/numeric.c
@@ -2483,11 +2483,7 @@ rb_int_floor(VALUE num, int ndigits)
static VALUE
rb_int_ceil(VALUE num, int ndigits)
{
- VALUE f;
-
- if (int_round_zero_p(num, ndigits))
- return INT2FIX(0);
- f = int_pow(10, -ndigits);
+ VALUE f = int_pow(10, -ndigits);
if (FIXNUM_P(num) && FIXNUM_P(f)) {
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
int neg = x < 0;
@@ -2497,11 +2493,16 @@ rb_int_ceil(VALUE num, int ndigits)
if (neg) x = -x;
return LONG2NUM(x);
}
- if (RB_FLOAT_TYPE_P(f)) {
- /* then int_pow overflow */
- return INT2FIX(0);
+ else {
+ bool neg = int_neg_p(num);
+ if (neg)
+ num = rb_int_uminus(num);
+ else
+ num = rb_int_plus(num, rb_int_minus(f, INT2FIX(1)));
+ num = rb_int_mul(rb_int_div(num, f), f);
+ if (neg) num = rb_int_uminus(num);
+ return num;
}
- return rb_int_plus(num, rb_int_minus(f, rb_int_modulo(num, f)));
}
VALUE