1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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.




git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42858 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2013-09-06 12:07:08 +00:00
parent 5aadc9d4ba
commit 42a3e0dc55
7 changed files with 153 additions and 1 deletions

View file

@ -1,3 +1,19 @@
Fri Sep 6 21:04:10 2013 Tanaka Akira <akr@fsij.org>
* 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@ruby-lang.org> Fri Sep 6 14:23:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
* win32/win32.c (clock_getres): required as well as clock_gettime(). * win32/win32.c (clock_getres): required as well as clock_gettime().

View file

@ -0,0 +1,3 @@
$(OBJS): $(HDRS) $(ruby_headers)
rat.o: rat.c $(top_srcdir)/internal.h

View file

@ -0,0 +1,7 @@
$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")

36
ext/-test-/rational/rat.c Normal file
View file

@ -0,0 +1,36 @@
#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);
}

View file

@ -733,6 +733,12 @@ int rb_execarg_run_options(const struct rb_execarg *e, struct rb_execarg *s, cha
VALUE rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash); VALUE rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash);
void rb_execarg_setenv(VALUE execarg_obj, VALUE env); 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 */ /* util.c */
extern const signed char ruby_digit36_to_number_table[]; extern const signed char ruby_digit36_to_number_table[];

View file

@ -17,10 +17,17 @@
#define NDEBUG #define NDEBUG
#include <assert.h> #include <assert.h>
#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
#define USE_GMP
#include <gmp.h>
#endif
#define ZERO INT2FIX(0) #define ZERO INT2FIX(0)
#define ONE INT2FIX(1) #define ONE INT2FIX(1)
#define TWO INT2FIX(2) #define TWO INT2FIX(2)
#define GMP_GCD_DIGITS 1
VALUE rb_cRational; VALUE rb_cRational;
static ID id_abs, id_cmp, id_convert, id_eqeq_p, id_expt, id_fdiv, static ID id_abs, id_cmp, id_convert, id_eqeq_p, id_expt, id_fdiv,
@ -276,6 +283,32 @@ k_rational_p(VALUE x)
#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x)) #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)) #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 #ifndef NDEBUG
#define f_gcd f_gcd_orig #define f_gcd f_gcd_orig
#endif #endif
@ -302,7 +335,7 @@ i_gcd(long x, long y)
} }
inline static VALUE inline static VALUE
f_gcd(VALUE x, VALUE y) f_gcd_normal(VALUE x, VALUE y)
{ {
VALUE z; VALUE z;
@ -333,6 +366,26 @@ f_gcd(VALUE x, VALUE y)
/* NOTREACHED */ /* 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 #ifndef NDEBUG
#undef f_gcd #undef f_gcd

View file

@ -0,0 +1,31 @@
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