diff options
author | Peter Zhu <[email protected]> | 2024-07-26 11:10:39 -0400 |
---|---|---|
committer | Peter Zhu <[email protected]> | 2024-07-30 08:21:28 -0400 |
commit | 3af2a7fbe12e11bac7b26bd991d3d02349f47295 (patch) | |
tree | a823090e82d8c0dcdbaa248119d3a99c37b887de /numeric.c | |
parent | 1870505f478cc75993b296b7144a45137ace6937 (diff) |
Fix floor when ndigits is large
[Bug #20654]
This commit fixes Integer#floor and Float#floor 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.floor(-5) # => -100000
puts -1.floor(-10) # => -10000000000
puts -1.floor(-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.c | 16 |
1 files changed, 7 insertions, 9 deletions
@@ -2462,11 +2462,7 @@ rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode) static VALUE rb_int_floor(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; @@ -2475,11 +2471,13 @@ rb_int_floor(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_minus(rb_int_plus(rb_int_uminus(num), 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_minus(num, rb_int_modulo(num, f)); } static VALUE |