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

ruby-changes:22964

From: marcandre <ko1@a...>
Date: Wed, 14 Mar 2012 15:10:13 +0900 (JST)
Subject: [ruby-changes:22964] marcandRe: r35013 (trunk): * numeric.c: fix flodivmod for cornercases [Bug #6044]

marcandre	2012-03-14 15:10:01 +0900 (Wed, 14 Mar 2012)

  New Revision: 35013

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35013

  Log:
    * numeric.c: fix flodivmod for cornercases [Bug #6044]
      add ruby_float_mod
    
    * insns.def (opt_mod): use ruby_float_mod
    
    * internal.h: declare ruby_float_mod
    
    * test/ruby/test_float.rb: tests for above
    
    * test/ruby/envutil.rb: create helper assert_is_minus_zero

  Modified files:
    trunk/ChangeLog
    trunk/insns.def
    trunk/internal.h
    trunk/numeric.c
    trunk/test/ruby/envutil.rb
    trunk/test/ruby/test_float.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 35012)
+++ ChangeLog	(revision 35013)
@@ -1,3 +1,16 @@
+Wed Mar 14 15:09:23 2012  Marc-Andre Lafortune  <ruby-core@m...>
+
+	* numeric.c: fix flodivmod for cornercases [Bug #6044]
+	  add ruby_float_mod
+
+	* insns.def (opt_mod): use ruby_float_mod
+
+	* internal.h: declare ruby_float_mod
+
+	* test/ruby/test_float.rb: tests for above
+
+	* test/ruby/envutil.rb: create helper assert_is_minus_zero
+
 Wed Mar 14 10:44:35 2012  Nobuyoshi Nakada  <nobu@r...>
 
 	* enumerator.c (lazy_grep_func): should use === instead of =~, as
Index: insns.def
===================================================================
--- insns.def	(revision 35012)
+++ insns.def	(revision 35013)
@@ -1618,23 +1618,7 @@
 	else if (HEAP_CLASS_OF(recv) == rb_cFloat &&
 		 HEAP_CLASS_OF(obj) == rb_cFloat &&
 		 BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) {
-	    double x = RFLOAT_VALUE(recv);
-	    double y = RFLOAT_VALUE(obj);
-	    double div, mod;
-
-	    {
-		double z;
-
-		modf(x / y, &z);
-		mod = x - z * y;
-	    }
-
-	    div = (x - mod) / y;
-	    if (y * mod < 0) {
-		mod += y;
-		div -= 1.0;
-	    }
-	    val = DBL2NUM(mod);
+	    val = DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)));
 	}
 	else {
 	    goto INSN_LABEL(normal_dispatch);
Index: numeric.c
===================================================================
--- numeric.c	(revision 35012)
+++ numeric.c	(revision 35013)
@@ -817,7 +817,9 @@
 #ifdef HAVE_FMOD
     mod = fmod(x, y);
 #else
-    {
+    if((x == 0.0) || (isinf(y) && !isinf(x)))
+        mod = x;
+    else {
 	double z;
 
 	modf(x/y, &z);
@@ -836,7 +838,18 @@
     if (divp) *divp = div;
 }
 
+/*
+ * Returns the modulo of division of x by y.
+ * An error will be raised if y == 0.
+ */
 
+double ruby_float_mod(double x, double y) {
+    double mod;
+    flodivmod(x, y, 0, &mod);
+    return mod;
+}
+
+
 /*
  *  call-seq:
  *     flt % other        ->  float
@@ -851,7 +864,7 @@
 static VALUE
 flo_mod(VALUE x, VALUE y)
 {
-    double fy, mod;
+    double fy;
 
     switch (TYPE(y)) {
       case T_FIXNUM:
@@ -866,8 +879,7 @@
       default:
 	return rb_num_coerce_bin(x, y, '%');
     }
-    flodivmod(RFLOAT_VALUE(x), fy, 0, &mod);
-    return DBL2NUM(mod);
+    return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(x), fy));
 }
 
 static VALUE
@@ -2733,12 +2745,7 @@
 	x = rb_int2big(FIX2LONG(x));
 	return rb_big_modulo(x, y);
       case T_FLOAT:
-	{
-	    double mod;
-
-	    flodivmod((double)FIX2LONG(x), RFLOAT_VALUE(y), 0, &mod);
-	    return DBL2NUM(mod);
-	}
+	return DBL2NUM(ruby_float_mod((double)FIX2LONG(x), RFLOAT_VALUE(y)));
       default:
 	return rb_num_coerce_bin(x, y, '%');
     }
Index: internal.h
===================================================================
--- internal.h	(revision 35012)
+++ internal.h	(revision 35013)
@@ -136,6 +136,7 @@
 /* numeric.c */
 int rb_num_to_uint(VALUE val, unsigned int *ret);
 int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl);
+double ruby_float_mod(double x, double y);
 
 /* object.c */
 VALUE rb_obj_equal(VALUE obj1, VALUE obj2);
Index: test/ruby/test_float.rb
===================================================================
--- test/ruby/test_float.rb	(revision 35012)
+++ test/ruby/test_float.rb	(revision 35013)
@@ -195,6 +195,18 @@
     assert_raise(TypeError) { 2.0.send(:%, nil) }
   end
 
+  def test_modulo3
+    bug6048 = '[ruby-core:42726]'
+    assert_equal(4.2, 4.2.send(:%, Float::INFINITY))
+    assert_equal(4.2, 4.2 % Float::INFINITY)
+    assert_is_minus_zero(-0.0 % 4.2)
+    assert_is_minus_zero(-0.0.send :%, 4.2)
+    assert_raise(ZeroDivisionError) { 4.2.send(:%, 0.0) }
+    assert_raise(ZeroDivisionError) { 4.2 % 0.0 }
+    assert_raise(ZeroDivisionError) { 42.send(:%, 0) }
+    assert_raise(ZeroDivisionError) { 42 % 0 }
+  end
+
   def test_divmod2
     assert_equal([1.0, 0.0], 2.0.divmod(2))
     assert_equal([1.0, 0.0], 2.0.divmod((2**32).coerce(2).first))
Index: test/ruby/envutil.rb
===================================================================
--- test/ruby/envutil.rb	(revision 35012)
+++ test/ruby/envutil.rb	(revision 35013)
@@ -212,6 +212,10 @@
         assert_equal([true, ""], [status.success?, err], message)
         assert_operator(after.fdiv(before), :<, limit, message)
       end
+
+      def assert_is_minus_zero(f)
+        assert(1.0/f == -Float::INFINITY, "#{f} is not -0.0")
+      end
     end
   end
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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