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.
This commit is contained in:
parent
1870505f47
commit
3af2a7fbe1
Notes:
git
2024-07-30 12:21:46 +00:00
16
numeric.c
16
numeric.c
@ -2462,11 +2462,7 @@ rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
|
|||||||
static VALUE
|
static VALUE
|
||||||
rb_int_floor(VALUE num, int ndigits)
|
rb_int_floor(VALUE num, int ndigits)
|
||||||
{
|
{
|
||||||
VALUE f;
|
VALUE f = int_pow(10, -ndigits);
|
||||||
|
|
||||||
if (int_round_zero_p(num, ndigits))
|
|
||||||
return INT2FIX(0);
|
|
||||||
f = int_pow(10, -ndigits);
|
|
||||||
if (FIXNUM_P(num) && FIXNUM_P(f)) {
|
if (FIXNUM_P(num) && FIXNUM_P(f)) {
|
||||||
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
|
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
|
||||||
int neg = x < 0;
|
int neg = x < 0;
|
||||||
@ -2475,11 +2471,13 @@ rb_int_floor(VALUE num, int ndigits)
|
|||||||
if (neg) x = -x;
|
if (neg) x = -x;
|
||||||
return LONG2NUM(x);
|
return LONG2NUM(x);
|
||||||
}
|
}
|
||||||
if (RB_FLOAT_TYPE_P(f)) {
|
else {
|
||||||
/* then int_pow overflow */
|
bool neg = int_neg_p(num);
|
||||||
return INT2FIX(0);
|
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
|
static VALUE
|
||||||
|
@ -530,6 +530,10 @@ class TestFloat < Test::Unit::TestCase
|
|||||||
assert_raise(TypeError) {1.0.floor(nil)}
|
assert_raise(TypeError) {1.0.floor(nil)}
|
||||||
def (prec = Object.new).to_int; 2; end
|
def (prec = Object.new).to_int; 2; end
|
||||||
assert_equal(0.99, 0.998.floor(prec))
|
assert_equal(0.99, 0.998.floor(prec))
|
||||||
|
|
||||||
|
assert_equal(-10000000000, -1.0.floor(-10), "[Bug #20654]")
|
||||||
|
assert_equal(-100000000000000000000, -1.0.floor(-20), "[Bug #20654]")
|
||||||
|
assert_equal(-100000000000000000000000000000000000000000000000000, -1.0.floor(-50), "[Bug #20654]")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ceil_with_precision
|
def test_ceil_with_precision
|
||||||
|
@ -465,6 +465,10 @@ class TestInteger < Test::Unit::TestCase
|
|||||||
|
|
||||||
assert_int_equal(1111_1111_1111_1111_1111_1111_1111_1111, 1111_1111_1111_1111_1111_1111_1111_1111.floor(1))
|
assert_int_equal(1111_1111_1111_1111_1111_1111_1111_1111, 1111_1111_1111_1111_1111_1111_1111_1111.floor(1))
|
||||||
assert_int_equal(10**400, (10**400).floor(1))
|
assert_int_equal(10**400, (10**400).floor(1))
|
||||||
|
|
||||||
|
assert_int_equal(-10000000000, -1.floor(-10), "[Bug #20654]")
|
||||||
|
assert_int_equal(-100000000000000000000, -1.floor(-20), "[Bug #20654]")
|
||||||
|
assert_int_equal(-100000000000000000000000000000000000000000000000000, -1.floor(-50), "[Bug #20654]")
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ceil
|
def test_ceil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user