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.
This commit is contained in:
parent
3af2a7fbe1
commit
a7167d0cee
Notes:
git
2024-07-30 12:21:45 +00:00
19
numeric.c
19
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
|
||||
|
@ -561,6 +561,10 @@ class TestFloat < Test::Unit::TestCase
|
||||
assert_raise(TypeError) {1.0.ceil(nil)}
|
||||
def (prec = Object.new).to_int; 2; end
|
||||
assert_equal(0.99, 0.981.ceil(prec))
|
||||
|
||||
assert_equal(10000000000, 1.0.ceil(-10), "[Bug #20654]")
|
||||
assert_equal(100000000000000000000, 1.0.ceil(-20), "[Bug #20654]")
|
||||
assert_equal(100000000000000000000000000000000000000000000000000, 1.0.ceil(-50), "[Bug #20654]")
|
||||
end
|
||||
|
||||
def test_truncate_with_precision
|
||||
|
@ -525,6 +525,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.truncate(1))
|
||||
assert_int_equal(10**400, (10**400).truncate(1))
|
||||
|
||||
assert_int_equal(10000000000, 1.ceil(-10), "[Bug #20654]")
|
||||
assert_int_equal(100000000000000000000, 1.ceil(-20), "[Bug #20654]")
|
||||
assert_int_equal(100000000000000000000000000000000000000000000000000, 1.ceil(-50), "[Bug #20654]")
|
||||
end
|
||||
|
||||
MimicInteger = Struct.new(:to_int)
|
||||
|
Loading…
x
Reference in New Issue
Block a user