summaryrefslogtreecommitdiff
path: root/rational.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-09-06 12:07:08 (GMT)
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-09-06 12:07:08 (GMT)
commit42a3e0dc55620664af3e6253f324711316b93934 (patch)
tree28c825e69d739e1f06d14f9f221974f6752d92c6 /rational.c
parent5aadc9d4ba39cfbdf0db64989bae945a165a0e65 (diff)
* 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
Diffstat (limited to 'rational.c')
-rw-r--r--rational.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/rational.c b/rational.c
index ee0e168..d70dfd4 100644
--- a/rational.c
+++ b/rational.c
@@ -17,10 +17,17 @@
#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)
#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)
}
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)
/* 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