From 603f95a0ed37d90854f80393881fb38ab29128a7 Mon Sep 17 00:00:00 2001 From: nobu Date: Tue, 2 Oct 2018 16:42:21 +0000 Subject: Fix Rational of Float [ruby-core:89239] [Bug #15189] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64897 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- bignum.c | 10 ++++++++-- numeric.c | 9 +++++---- object.c | 15 ++++++++++++--- rational.c | 21 ++++++++++++++++++--- test/ruby/test_integer.rb | 23 +++++++++++++++++++++++ 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/bignum.c b/bignum.c index ee481e1bd7..e53b2bd2c1 100644 --- a/bignum.c +++ b/bignum.c @@ -6207,6 +6207,7 @@ rb_big_pow(VALUE x, VALUE y) again: if (y == INT2FIX(0)) return INT2FIX(1); + if (y == INT2FIX(1)) return x; if (RB_FLOAT_TYPE_P(y)) { d = RFLOAT_VALUE(y); if ((BIGNUM_NEGATIVE_P(x) && !BIGZEROP(x))) { @@ -6223,8 +6224,13 @@ rb_big_pow(VALUE x, VALUE y) else if (FIXNUM_P(y)) { yy = FIX2LONG(y); - if (yy < 0) - return rb_rational_raw(INT2FIX(1), rb_big_pow(x, INT2NUM(-yy))); + if (yy < 0) { + x = rb_big_pow(x, INT2NUM(-yy)); + if (RB_INTEGER_TYPE_P(x)) + return rb_rational_raw(INT2FIX(1), x); + else + return DBL2NUM(1.0 / NUM2DBL(x)); + } else { VALUE z = 0; SIGNED_VALUE mask; diff --git a/numeric.c b/numeric.c index c8a240b778..292af0af27 100644 --- a/numeric.c +++ b/numeric.c @@ -4015,7 +4015,8 @@ fix_pow(VALUE x, VALUE y) } if (b < 0) { if (a == 0) rb_num_zerodiv(); - return rb_rational_raw(INT2FIX(1), rb_int_pow(x, LONG2NUM(-b))); + y = rb_int_pow(x, LONG2NUM(-b)); + goto inverted; } if (b == 0) return INT2FIX(1); @@ -4035,10 +4036,10 @@ fix_pow(VALUE x, VALUE y) if (BIGNUM_NEGATIVE_P(y)) { if (a == 0) rb_num_zerodiv(); y = rb_int_pow(x, rb_big_uminus(y)); - if (0 && RB_FLOAT_TYPE_P(y)) { - /* Maybe should return a Float */ + inverted: + if (RB_FLOAT_TYPE_P(y)) { double d = pow((double)a, RFLOAT_VALUE(y)); - return DBL2NUM(d); + return DBL2NUM(1.0 / d); } return rb_rational_raw(INT2FIX(1), y); } diff --git a/object.c b/object.c index 7d6e47932c..6a66159a94 100644 --- a/object.c +++ b/object.c @@ -3421,9 +3421,18 @@ rb_str_to_dbl(VALUE str, int badcheck) #define big2dbl_without_to_f(x) rb_big2dbl(x) #define int2dbl_without_to_f(x) \ (FIXNUM_P(x) ? fix2dbl_without_to_f(x) : big2dbl_without_to_f(x)) -#define rat2dbl_without_to_f(x) \ - (int2dbl_without_to_f(rb_rational_num(x)) / \ - int2dbl_without_to_f(rb_rational_den(x))) +static inline double +rat2dbl_without_to_f(VALUE x) +{ + VALUE num = rb_rational_num(x); + VALUE den = rb_rational_den(x); + if (RB_INTEGER_TYPE_P(num) && RB_INTEGER_TYPE_P(den)) { + return int2dbl_without_to_f(num) / int2dbl_without_to_f(den); + } + else { + return NUM2DBL(num) / NUM2DBL(den); + } +} #define special_const_to_float(val, pre, post) \ switch (val) { \ diff --git a/rational.c b/rational.c index 3fcf82bce5..6426f2327c 100644 --- a/rational.c +++ b/rational.c @@ -696,7 +696,8 @@ f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) a = rb_int_idiv(bden, g); den = rb_int_mul(a, b); } - else { + else if (RB_INTEGER_TYPE_P(anum) && RB_INTEGER_TYPE_P(aden) && + RB_INTEGER_TYPE_P(bnum) && RB_INTEGER_TYPE_P(bden)) { VALUE g = f_gcd(aden, bden); VALUE a = rb_int_mul(anum, rb_int_idiv(bden, g)); VALUE b = rb_int_mul(bnum, rb_int_idiv(aden, g)); @@ -713,6 +714,12 @@ f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) a = rb_int_idiv(bden, g); den = rb_int_mul(a, b); } + else { + double a = NUM2DBL(anum) / NUM2DBL(aden); + double b = NUM2DBL(bnum) / NUM2DBL(bden); + double c = k == '+' ? a + b : a - b; + return DBL2NUM(c); + } return f_rational_new_no_reduce2(CLASS_OF(self), num, den); } @@ -1144,9 +1151,9 @@ static VALUE nurat_eqeq_p(VALUE self, VALUE other) { if (RB_INTEGER_TYPE_P(other)) { - { - get_dat1(self); + get_dat1(self); + if (RB_INTEGER_TYPE_P(dat->num) && RB_INTEGER_TYPE_P(dat->den)) { if (INT_ZERO_P(dat->num) && INT_ZERO_P(other)) return Qtrue; @@ -1156,6 +1163,10 @@ nurat_eqeq_p(VALUE self, VALUE other) return Qfalse; return rb_int_equal(dat->num, other); } + else { + const double d = nurat_to_double(self); + return f_boolcast(FIXNUM_ZERO_P(rb_dbl_cmp(d, NUM2DBL(other)))); + } } else if (RB_FLOAT_TYPE_P(other)) { const double d = nurat_to_double(self); @@ -1544,6 +1555,10 @@ static double nurat_to_double(VALUE self) { get_dat1(self); + if (!RB_INTEGER_TYPE_P(dat->num) || !RB_INTEGER_TYPE_P(dat->den)) { + double d = NUM2DBL(dat->num) / NUM2DBL(dat->den); + return DBL2NUM(d); + } return rb_int_fdiv_double(dat->num, dat->den); } diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index acba5aca1a..a991683773 100644 --- a/test/ruby/test_integer.rb +++ b/test/ruby/test_integer.rb @@ -27,6 +27,29 @@ class TestInteger < Test::Unit::TestCase x = EnvUtil.suppress_warning {2 ** -0x4000000000000000} assert_in_delta(0.0, (x / 2), Float::EPSILON) + + <<~EXPRS.each_line.with_index(__LINE__+1) do |expr, line| + crash01: 111r+11**-11111161111111 + crash02: 1118111111111**-1111111111111111**1+1==11111 + crash03: -1111111**-1111*11 - -1111111** -111111111 + crash04: 1118111111111** -1111111111111111**1+11111111111**1 ===111 + crash05: 11** -111155555555555555 -55 !=5-555 + crash07: 1 + 111111111**-1111811111 + crash08: 18111111111**-1111111111111111**1 + 1111111111**-1111**1 + crash10: -7 - -1111111** -1111**11 + crash12: 1118111111111** -1111111111111111**1 + 1111 - -1111111** -1111*111111111119 + crash13: 1.0i - -1111111** -111111111 + crash14: 11111**111111111**111111 * -11111111111111111111**-111111111111 + crash15: ~1**1111 + -~1**~1**111 + crash17: 11** -1111111**1111 /11i + crash18: 5555i**-5155 - -9111111**-1111**11 + crash19: 111111*-11111111111111111111**-1111111111111111 + crash20: 1111**111-11**-11111**11 + crash21: 11**-10111111119-1i -1r + EXPRS + name, expr = expr.split(':', 2) + assert_ruby_status(%w"-W0", expr, name) + end end def test_lshift -- cgit v1.2.3