ruby-changes:27011
From: marcandre <ko1@a...>
Date: Tue, 5 Feb 2013 14:39:41 +0900 (JST)
Subject: [ruby-changes:27011] marcandRe: r39063 (trunk): * rational.c (nurat_expt): Deal with special cases for rationals 0, ?\194?\1771
marcandre 2013-02-05 14:39:33 +0900 (Tue, 05 Feb 2013) New Revision: 39063 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=39063 Log: * rational.c (nurat_expt): Deal with special cases for rationals 0, ?\194?\1771 [bug #5713] [bug #5715] Modified files: trunk/rational.c trunk/test/ruby/test_rational.rb Index: test/ruby/test_rational.rb =================================================================== --- test/ruby/test_rational.rb (revision 39062) +++ test/ruby/test_rational.rb (revision 39063) @@ -1143,6 +1143,26 @@ class Rational_Test < Test::Unit::TestCa https://github.com/ruby/ruby/blob/trunk/test/ruby/test_rational.rb#L1143 assert_equal(1.0, Rational(n + 2, n + 1).to_f, '[ruby-dev:33852]') end + def test_power_of_1_and_minus_1 + bug5715 = '[ruby-core:41498]' + big = 1 << 66 + one = Rational( 1, 1) + assert_eql one, one ** -big , bug5715 + assert_eql one, (-one) ** -big , bug5715 + assert_eql -one, (-one) ** -(big+1) , bug5715 + assert_equal Complex, ((-one) ** Rational(1,3)).class + end + + def test_power_of_0 + bug5713 = '[ruby-core:41494]' + big = 1 << 66 + zero = Rational(0, 1) + assert_eql zero, zero ** big + assert_eql zero, zero ** Rational(2, 3) + assert_raise(ZeroDivisionError, bug5713) { Rational(0, 1) ** -big } + assert_raise(ZeroDivisionError, bug5713) { Rational(0, 1) ** Rational(-2,3) } + end + def test_known_bug end Index: rational.c =================================================================== --- rational.c (revision 39062) +++ rational.c (revision 39063) @@ -221,6 +221,26 @@ f_one_p(VALUE x) https://github.com/ruby/ruby/blob/trunk/rational.c#L221 } inline static VALUE +f_minus_one_p(VALUE x) +{ + switch (TYPE(x)) { + case T_FIXNUM: + return f_boolcast(FIX2LONG(x) == -1); + case T_BIGNUM: + return Qfalse; + case T_RATIONAL: + { + VALUE num = RRATIONAL(x)->num; + VALUE den = RRATIONAL(x)->den; + + return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == -1 && + FIXNUM_P(den) && FIX2LONG(den) == 1); + } + } + return rb_funcall(x, id_eqeq_p, 1, INT2FIX(-1)); +} + +inline static VALUE f_kind_of_p(VALUE x, VALUE c) { return rb_obj_is_kind_of(x, c); @@ -916,6 +936,16 @@ nurat_fdiv(VALUE self, VALUE other) https://github.com/ruby/ruby/blob/trunk/rational.c#L936 return f_to_f(f_div(self, other)); } +inline static VALUE +f_odd_p(VALUE integer) +{ + if (rb_funcall(integer, '%', 1, INT2FIX(2)) != INT2FIX(0)) { + return Qtrue; + } + return Qfalse; + +} + /* * call-seq: * rat ** numeric -> numeric @@ -942,6 +972,22 @@ nurat_expt(VALUE self, VALUE other) https://github.com/ruby/ruby/blob/trunk/rational.c#L972 other = dat->num; /* c14n */ } + /* Deal with special cases of 0**n and 1**n */ + if (k_numeric_p(other) && k_exact_p(other)) { + get_dat1(self); + if (f_one_p(dat->den)) + if (f_one_p(dat->num)) + return f_rational_new_bang1(CLASS_OF(self), ONE); + else if (f_minus_one_p(dat->num) && k_integer_p(other)) + return f_rational_new_bang1(CLASS_OF(self), INT2FIX(f_odd_p(other) ? -1 : 1)); + else if (f_zero_p(dat->num)) + if (FIX2INT(f_cmp(other, ZERO)) == -1) + rb_raise_zerodiv(); + else + return f_rational_new_bang1(CLASS_OF(self), ZERO); + } + + /* General case */ switch (TYPE(other)) { case T_FIXNUM: { -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/