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

ruby-changes:46807

From: watson1978 <ko1@a...>
Date: Sat, 27 May 2017 14:41:07 +0900 (JST)
Subject: [ruby-changes:46807] watson1978:r58922 (trunk): Improve performance of some Time & Rational methods

watson1978	2017-05-27 14:41:02 +0900 (Sat, 27 May 2017)

  New Revision: 58922

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=58922

  Log:
    Improve performance of some Time & Rational methods
    
    rational.c (i_gcd): replace GCD algorithm from Euclidean algorithm to Stein
        algorithm (https://en.wikipedia.org/wiki/Binary_GCD_algorithm).
    
        Some Time methods will call internal quov() function and it calls
        Rational#quo -> f_muldiv() -> i_gcd() in rational.c
        And some Rational methods also call i_gcd().
    
        The implementation of Euclidean algorithm spent a long time at modulo
        operation (ie "x = y % x;").
        The Stein algorithm will replace with shift operation which is faster
        than modulo.
    
        Time#subsec -> 36 % up
        Time#to_r   -> 26 % up
        Rational#+  -> 14 % up
        Rational#-  -> 15 % up
        Rational#*  -> 13 % up
    
        [ruby-core:80843] [Bug #13503] [Fix GH-1596]
    
    ### Before
             Time#subsec      2.142M (?\194?\177 9.8%) i/s -     10.659M in   5.022659s
               Time#to_r      2.003M (?\194?\177 9.1%) i/s -      9.959M in   5.012445s
              Rational#+      3.843M (?\194?\177 0.9%) i/s -     19.274M in   5.016254s
              Rational#-      3.820M (?\194?\177 1.3%) i/s -     19.149M in   5.014137s
              Rational#*      5.198M (?\194?\177 1.4%) i/s -     26.016M in   5.005664s
    * After
             Time#subsec      2.902M (?\194?\177 2.9%) i/s -     14.505M in   5.001815s
               Time#to_r      2.503M (?\194?\177 4.8%) i/s -     12.512M in   5.011454s
              Rational#+      4.390M (?\194?\177 1.2%) i/s -     22.001M in   5.012413s
              Rational#-      4.391M (?\194?\177 1.2%) i/s -     22.013M in   5.014584s
              Rational#*      5.872M (?\194?\177 2.2%) i/s -     29.369M in   5.003666s
    
    * Test code
    require 'benchmark/ips'
    
    Benchmark.ips do |x|
      x.report "Time#subsec" do |t|
        time = Time.now
        t.times { time.subsec }
      end
    
      x.report "Time#to_r" do |t|
        time = Time.now
        t.times { time.to_r }
      end
    
      x.report "Rational#+" do |t|
        rat1 = 1/2r
        rat2 = 1/3r
        t.times { rat1 + rat2 }
      end
    
      x.report "Rational#-" do |t|
        rat1 = 1/3r
        rat2 = 1/2r
        t.times { rat1 - rat2 }
      end
    
      x.report "Rational#*" do |t|
        rat1 = 1/3r
        rat2 = 1/2r
        t.times { rat1 * rat2 }
      end
    end

  Modified files:
    trunk/rational.c
Index: rational.c
===================================================================
--- rational.c	(revision 58921)
+++ rational.c	(revision 58922)
@@ -280,6 +280,9 @@ rb_gcd_gmp(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/rational.c#L280
 inline static long
 i_gcd(long x, long y)
 {
+    unsigned long u, v, t;
+    int shift;
+
     if (x < 0)
 	x = -x;
     if (y < 0)
@@ -290,12 +293,29 @@ i_gcd(long x, long y) https://github.com/ruby/ruby/blob/trunk/rational.c#L293
     if (y == 0)
 	return x;
 
-    while (x > 0) {
-	long t = x;
-	x = y % x;
-	y = t;
+    u = (unsigned long)x;
+    v = (unsigned long)y;
+    for (shift = 0; ((u | v) & 1) == 0; ++shift) {
+	u >>= 1;
+	v >>= 1;
     }
-    return y;
+
+    while ((u & 1) == 0)
+	u >>= 1;
+
+    do {
+	while ((v & 1) == 0)
+	    v >>= 1;
+
+	if (u > v) {
+	    t = v;
+	    v = u;
+	    u = t;
+	}
+	v = v - u;
+    } while (v != 0);
+
+    return (long)(u << shift);
 }
 
 inline static VALUE

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

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