summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--bignum.c55
-rw-r--r--ext/-test-/bignum/big2str.c14
-rw-r--r--internal.h7
4 files changed, 83 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 8b5160346d..d67fffbdfe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Sun Sep 1 23:30:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (GMP_BIG2STR_DIGITS): New constant.
+ (big2str_gmp): New function.
+ (rb_big2str1): Use big2str_gmp for big bignums.
+
+ * internal.h (rb_big2str_gmp): Declared.
+
+ * ext/-test-/bignum/big2str.c (big2str_gmp): New method.
+
Sun Sep 1 22:37:51 2013 Tanaka Akira <akr@fsij.org>
* bignum.c (bary_mul_gmp): Use mpz_init and mpz_clear instead of
diff --git a/bignum.c b/bignum.c
index 7a6e1f2934..ecb338a791 100644
--- a/bignum.c
+++ b/bignum.c
@@ -135,6 +135,8 @@ STATIC_ASSERT(sizeof_long_and_sizeof_bdigit, SIZEOF_BDIGITS % SIZEOF_LONG == 0);
#define KARATSUBA_MUL_DIGITS 70
#define TOOM3_MUL_DIGITS 150
+#define GMP_BIG2STR_DIGITS 20
+
typedef void (mulfunc_t)(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const BDIGIT *yds, size_t yn, BDIGIT *wds, size_t wn);
static mulfunc_t bary_mul_toom3_start;
@@ -4466,6 +4468,50 @@ rb_big2str_generic(VALUE x, int base)
return big2str_generic(x, base, xds, xn);
}
+#ifdef USE_GMP
+VALUE
+big2str_gmp(int negative_p, int base, BDIGIT *xds, size_t xn)
+{
+ const size_t nails = (sizeof(BDIGIT)-SIZEOF_BDIGITS)*CHAR_BIT;
+ mpz_t x;
+ size_t size;
+ VALUE str;
+ char *p;
+
+ mpz_init(x);
+ mpz_import(x, xn, -1, sizeof(BDIGIT), 0, nails, xds);
+
+ size = mpz_sizeinbase(x, base);
+
+ if (negative_p) {
+ str = rb_usascii_str_new(0, size+1);
+ p = RSTRING_PTR(str);
+ *p++ = '-';
+ }
+ else {
+ str = rb_usascii_str_new(0, size);
+ p = RSTRING_PTR(str);
+ }
+ mpz_get_str(p, base, x);
+ mpz_clear(x);
+
+ if (RSTRING_PTR(str)[RSTRING_LEN(str)-1] == '\0') {
+ rb_str_set_len(str, RSTRING_LEN(str)-1);
+ }
+
+ return str;
+}
+
+VALUE
+rb_big2str_gmp(VALUE x, int base)
+{
+ VALUE str;
+ str = big2str_gmp(RBIGNUM_NEGATIVE_P(x), base, BDIGITS(x), RBIGNUM_LEN(x));
+ RB_GC_GUARD(x);
+ return str;
+}
+#endif
+
static VALUE
rb_big2str1(VALUE x, int base)
{
@@ -4496,6 +4542,15 @@ rb_big2str1(VALUE x, int base)
return big2str_base_poweroftwo(x, base);
}
+#ifdef USE_GMP
+ if (GMP_BIG2STR_DIGITS < xn) {
+ VALUE str;
+ str = big2str_gmp(RBIGNUM_NEGATIVE_P(x), base, xds, xn);
+ RB_GC_GUARD(x);
+ return str;
+ }
+#endif
+
return big2str_generic(x, base, xds, xn);
}
diff --git a/ext/-test-/bignum/big2str.c b/ext/-test-/bignum/big2str.c
index 2c5df6a656..794b4e8b22 100644
--- a/ext/-test-/bignum/big2str.c
+++ b/ext/-test-/bignum/big2str.c
@@ -32,9 +32,23 @@ big2str_poweroftwo(VALUE x, VALUE vbase)
return rb_big2str_poweroftwo(big(x), NUM2INT(vbase));
}
+#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
+static VALUE
+big2str_gmp(VALUE x, VALUE vbase)
+{
+ int base = NUM2INT(vbase);
+ if (base < 2 || 36 < base)
+ rb_raise(rb_eArgError, "invalid radix %d", base);
+ return rb_big2str_gmp(big(x), NUM2INT(vbase));
+}
+#else
+#define mul_gmp rb_f_notimplement
+#endif
+
void
Init_big2str(VALUE klass)
{
rb_define_method(rb_cInteger, "big2str_generic", big2str_generic, 1);
rb_define_method(rb_cInteger, "big2str_poweroftwo", big2str_poweroftwo, 1);
+ rb_define_method(rb_cInteger, "big2str_gmp", big2str_gmp, 1);
}
diff --git a/internal.h b/internal.h
index db3fa0b670..877611081f 100644
--- a/internal.h
+++ b/internal.h
@@ -644,12 +644,13 @@ VALUE rb_big_mul_normal(VALUE x, VALUE y);
VALUE rb_big_mul_balance(VALUE x, VALUE y);
VALUE rb_big_mul_karatsuba(VALUE x, VALUE y);
VALUE rb_big_mul_toom3(VALUE x, VALUE y);
-#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
-VALUE rb_big_mul_gmp(VALUE x, VALUE y);
-#endif
VALUE rb_big_sq_fast(VALUE x);
VALUE rb_big2str_poweroftwo(VALUE x, int base);
VALUE rb_big2str_generic(VALUE x, int base);
+#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
+VALUE rb_big_mul_gmp(VALUE x, VALUE y);
+VALUE rb_big2str_gmp(VALUE x, int base);
+#endif
/* file.c */
#ifdef __APPLE__