ruby-changes:52685
From: nobu <ko1@a...>
Date: Wed, 3 Oct 2018 01:42:28 +0900 (JST)
Subject: [ruby-changes:52685] nobu:r64897 (trunk): Fix Rational of Float
nobu 2018-10-03 01:42:21 +0900 (Wed, 03 Oct 2018) New Revision: 64897 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64897 Log: Fix Rational of Float [ruby-core:89239] [Bug #15189] Modified files: trunk/bignum.c trunk/numeric.c trunk/object.c trunk/rational.c trunk/test/ruby/test_integer.rb Index: bignum.c =================================================================== --- bignum.c (revision 64896) +++ bignum.c (revision 64897) @@ -6207,6 +6207,7 @@ rb_big_pow(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/bignum.c#L6207 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) https://github.com/ruby/ruby/blob/trunk/bignum.c#L6224 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; Index: numeric.c =================================================================== --- numeric.c (revision 64896) +++ numeric.c (revision 64897) @@ -4015,7 +4015,8 @@ fix_pow(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L4015 } 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) https://github.com/ruby/ruby/blob/trunk/numeric.c#L4036 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); } Index: object.c =================================================================== --- object.c (revision 64896) +++ object.c (revision 64897) @@ -3421,9 +3421,18 @@ rb_str_to_dbl(VALUE str, int badcheck) https://github.com/ruby/ruby/blob/trunk/object.c#L3421 #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) { \ Index: test/ruby/test_integer.rb =================================================================== --- test/ruby/test_integer.rb (revision 64896) +++ test/ruby/test_integer.rb (revision 64897) @@ -27,6 +27,29 @@ class TestInteger < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_integer.rb#L27 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 Index: rational.c =================================================================== --- rational.c (revision 64896) +++ rational.c (revision 64897) @@ -696,7 +696,8 @@ f_addsub(VALUE self, VALUE anum, VALUE a https://github.com/ruby/ruby/blob/trunk/rational.c#L696 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 a https://github.com/ruby/ruby/blob/trunk/rational.c#L714 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 https://github.com/ruby/ruby/blob/trunk/rational.c#L1151 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) https://github.com/ruby/ruby/blob/trunk/rational.c#L1163 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 https://github.com/ruby/ruby/blob/trunk/rational.c#L1555 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); } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/