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

ruby-changes:30779

From: akr <ko1@a...>
Date: Fri, 6 Sep 2013 21:07:15 +0900 (JST)
Subject: [ruby-changes:30779] akr:r42858 (trunk): * rational.c: Include gmp.h if GMP is used.

akr	2013-09-06 21:07:08 +0900 (Fri, 06 Sep 2013)

  New Revision: 42858

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

  Log:
    * rational.c: Include gmp.h if GMP is used.
      (GMP_GCD_DIGITS): New macro.
      (rb_gcd_gmp): New function.
      (f_gcd_normal): Renamed from f_gcd.
      (rb_gcd_normal): New function.
      (f_gcd): Invoke rb_gcd_gmp or f_gcd_normal.
    
    * internal.h (rb_gcd_normal): Declared.
      (rb_gcd_gmp): Ditto.
    
    * ext/-test-/rational: New directory.

  Added directories:
    trunk/ext/-test-/rational/
    trunk/test/-ext-/rational/
  Added files:
    trunk/ext/-test-/rational/depend
    trunk/ext/-test-/rational/extconf.rb
    trunk/ext/-test-/rational/rat.c
    trunk/test/-ext-/rational/test_rat.rb
  Modified files:
    trunk/ChangeLog
    trunk/internal.h
    trunk/rational.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 42857)
+++ ChangeLog	(revision 42858)
@@ -1,3 +1,19 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Sep  6 21:04:10 2013  Tanaka Akira  <akr@f...>
+
+	* rational.c: Include gmp.h if GMP is used.
+	  (GMP_GCD_DIGITS): New macro.
+	  (rb_gcd_gmp): New function.
+	  (f_gcd_normal): Renamed from f_gcd.
+	  (rb_gcd_normal): New function.
+	  (f_gcd): Invoke rb_gcd_gmp or f_gcd_normal.
+
+	* internal.h (rb_gcd_normal): Declared.
+	  (rb_gcd_gmp): Ditto.
+
+	* ext/-test-/rational: New directory.
+
+	* test/-ext-/rational: New directory.
+
 Fri Sep  6 14:23:22 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* win32/win32.c (clock_getres): required as well as clock_gettime().
Index: ext/-test-/rational/depend
===================================================================
--- ext/-test-/rational/depend	(revision 0)
+++ ext/-test-/rational/depend	(revision 42858)
@@ -0,0 +1,3 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/rational/depend#L1
+$(OBJS): $(HDRS) $(ruby_headers)
+
+rat.o: rat.c $(top_srcdir)/internal.h
Index: ext/-test-/rational/rat.c
===================================================================
--- ext/-test-/rational/rat.c	(revision 0)
+++ ext/-test-/rational/rat.c	(revision 42858)
@@ -0,0 +1,36 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/rational/rat.c#L1
+#include "ruby.h"
+#include "internal.h"
+
+static VALUE
+big(VALUE x)
+{
+    if (FIXNUM_P(x))
+        return rb_int2big(FIX2LONG(x));
+    if (RB_TYPE_P(x, T_BIGNUM))
+        return x;
+    rb_raise(rb_eTypeError, "can't convert %s to Bignum",
+            rb_obj_classname(x));
+}
+
+static VALUE
+gcd_normal(VALUE x, VALUE y)
+{
+    return rb_big_norm(rb_gcd_normal(rb_to_int(x), rb_to_int(y)));
+}
+
+#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
+static VALUE
+gcd_gmp(VALUE x, VALUE y)
+{
+    return rb_big_norm(rb_gcd_gmp(big(x), big(y)));
+}
+#else
+#define gcd_gmp rb_f_notimplement
+#endif
+
+void
+Init_rational(VALUE klass)
+{
+    rb_define_method(rb_cInteger, "gcd_normal", gcd_normal, 1);
+    rb_define_method(rb_cInteger, "gcd_gmp", gcd_gmp, 1);
+}
Index: ext/-test-/rational/extconf.rb
===================================================================
--- ext/-test-/rational/extconf.rb	(revision 0)
+++ ext/-test-/rational/extconf.rb	(revision 42858)
@@ -0,0 +1,7 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/rational/extconf.rb#L1
+$INCFLAGS << " -I$(topdir) -I$(top_srcdir)"
+$srcs = Dir[File.join($srcdir, "*.{#{SRC_EXT.join(%q{,})}}")]
+inits = $srcs.map {|s| File.basename(s, ".*")}
+inits.delete("init")
+inits.map! {|s|"X(#{s})"}
+$defs << "-DTEST_INIT_FUNCS(X)=\"#{inits.join(' ')}\""
+create_makefile("-test-/rational")
Index: internal.h
===================================================================
--- internal.h	(revision 42857)
+++ internal.h	(revision 42858)
@@ -733,6 +733,12 @@ int rb_execarg_run_options(const struct https://github.com/ruby/ruby/blob/trunk/internal.h#L733
 VALUE rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash);
 void rb_execarg_setenv(VALUE execarg_obj, VALUE env);
 
+/* rational.c */
+VALUE rb_gcd_normal(VALUE self, VALUE other);
+#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
+VALUE rb_gcd_gmp(VALUE x, VALUE y);
+#endif
+
 /* util.c */
 extern const signed char ruby_digit36_to_number_table[];
 
Index: test/-ext-/rational/test_rat.rb
===================================================================
--- test/-ext-/rational/test_rat.rb	(revision 0)
+++ test/-ext-/rational/test_rat.rb	(revision 42858)
@@ -0,0 +1,31 @@ https://github.com/ruby/ruby/blob/trunk/test/-ext-/rational/test_rat.rb#L1
+require 'test/unit'
+require "-test-/rational"
+
+class TestRational < Test::Unit::TestCase
+  class TestGCD < Test::Unit::TestCase
+
+    def test_gcd_normal
+      x = 2*2*3*3*3
+      y = 2*2*2*3*3
+      gcd = 2*2*3*3
+      assert_equal(gcd, x.gcd_normal(y))
+    end
+
+    def test_gcd_gmp
+      x = 2*2*3*3*3
+      y = 2*2*2*3*3
+      gcd = 2*2*3*3
+      assert_equal(gcd, x.gcd_gmp(y))
+    rescue NotImplementedError
+    end
+
+    def test_gcd_gmp_brute_force
+      -13.upto(13) {|x|
+        -13.upto(13) {|y|
+          assert_equal(x.gcd_normal(y), x.gcd_gmp(y))
+        }
+      }
+    rescue NotImplementedError
+    end
+  end
+end
Index: rational.c
===================================================================
--- rational.c	(revision 42857)
+++ rational.c	(revision 42858)
@@ -17,10 +17,17 @@ https://github.com/ruby/ruby/blob/trunk/rational.c#L17
 #define NDEBUG
 #include <assert.h>
 
+#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
+#define USE_GMP
+#include <gmp.h>
+#endif
+
 #define ZERO INT2FIX(0)
 #define ONE INT2FIX(1)
 #define TWO INT2FIX(2)
 
+#define GMP_GCD_DIGITS 1
+
 VALUE rb_cRational;
 
 static ID id_abs, id_cmp, id_convert, id_eqeq_p, id_expt, id_fdiv,
@@ -276,6 +283,32 @@ k_rational_p(VALUE x) https://github.com/ruby/ruby/blob/trunk/rational.c#L283
 #define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
 #define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
 
+#ifdef USE_GMP
+VALUE
+rb_gcd_gmp(VALUE x, VALUE y)
+{
+    const size_t nails = (sizeof(BDIGIT)-SIZEOF_BDIGITS)*CHAR_BIT;
+    mpz_t mx, my, mz;
+    size_t count;
+    VALUE z;
+    long zn;
+
+    mpz_init(mx);
+    mpz_init(my);
+    mpz_init(mz);
+    mpz_import(mx, RBIGNUM_LEN(x), -1, sizeof(BDIGIT), 0, nails, RBIGNUM_DIGITS(x));
+    mpz_import(my, RBIGNUM_LEN(y), -1, sizeof(BDIGIT), 0, nails, RBIGNUM_DIGITS(y));
+
+    mpz_gcd(mz, mx, my);
+
+    zn = (mpz_sizeinbase(mz, 16) + SIZEOF_BDIGITS*2 - 1) / (SIZEOF_BDIGITS*2);
+    z = rb_big_new(zn, 1);
+    mpz_export(RBIGNUM_DIGITS(z), &count, -1, sizeof(BDIGIT), 0, nails, mz);
+
+    return rb_big_norm(z);
+}
+#endif
+
 #ifndef NDEBUG
 #define f_gcd f_gcd_orig
 #endif
@@ -302,7 +335,7 @@ i_gcd(long x, long y) https://github.com/ruby/ruby/blob/trunk/rational.c#L335
 }
 
 inline static VALUE
-f_gcd(VALUE x, VALUE y)
+f_gcd_normal(VALUE x, VALUE y)
 {
     VALUE z;
 
@@ -333,6 +366,26 @@ f_gcd(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/rational.c#L366
     /* NOTREACHED */
 }
 
+VALUE
+rb_gcd_normal(VALUE x, VALUE y)
+{
+    return f_gcd_normal(x, y);
+}
+
+inline static VALUE
+f_gcd(VALUE x, VALUE y)
+{
+#ifdef USE_GMP
+    if (TYPE(x) == T_BIGNUM && TYPE(y) == T_BIGNUM) {
+        long xn = RBIGNUM_LEN(x);
+        long yn = RBIGNUM_LEN(y);
+        if (GMP_GCD_DIGITS <= xn && GMP_GCD_DIGITS <= yn)
+            return rb_gcd_gmp(x, y);
+    }
+#endif
+    return f_gcd_normal(x, y);
+}
+
 #ifndef NDEBUG
 #undef f_gcd
 

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

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