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/