diff options
| author | Peter Zhu <peter@peterzhu.ca> | 2024-07-26 11:10:53 -0400 |
|---|---|---|
| committer | nagachika <nagachika@ruby-lang.org> | 2024-08-02 18:26:26 +0900 |
| commit | 7fc6448ec7f7505ca5772af0a60ee780c321492c (patch) | |
| tree | c921386da7cc206a36cfb6bcf24bcb5579024576 /numeric.c | |
| parent | 7048fbdf59509e4f52eff56d7c044ed28eb67727 (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.
Diffstat (limited to 'numeric.c')
| -rw-r--r-- | numeric.c | 19 |
1 files changed, 10 insertions, 9 deletions
@@ -2393,11 +2393,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; @@ -2407,11 +2403,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 |
