[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]