ruby-changes:30727
From: akr <ko1@a...>
Date: Tue, 3 Sep 2013 20:20:16 +0900 (JST)
Subject: [ruby-changes:30727] akr:r42806 (trunk): * bignum.c (GMP_STR2BIG_DIGITS): New macro.
akr 2013-09-03 20:20:02 +0900 (Tue, 03 Sep 2013) New Revision: 42806 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=42806 Log: * bignum.c (GMP_STR2BIG_DIGITS): New macro. (str2big_gmp): New function. (rb_cstr_to_inum): Use str2big_gmp for big bignums. (rb_str2big_gmp): New function. * internal.h (rb_str2big_gmp): Declared. Modified files: trunk/ChangeLog trunk/bignum.c trunk/ext/-test-/bignum/str2big.c trunk/internal.h trunk/test/-ext-/bignum/test_str2big.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 42805) +++ ChangeLog (revision 42806) @@ -1,3 +1,12 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Tue Sep 3 20:12:46 2013 Tanaka Akira <akr@f...> + + * bignum.c (GMP_STR2BIG_DIGITS): New macro. + (str2big_gmp): New function. + (rb_cstr_to_inum): Use str2big_gmp for big bignums. + (rb_str2big_gmp): New function. + + * internal.h (rb_str2big_gmp): Declared. + Tue Sep 3 19:44:40 2013 NAKAMURA Usaku <usa@r...> * ext/win32/lib/win32/registry.rb (Win32::Registry#values): added. Index: ext/-test-/bignum/str2big.c =================================================================== --- ext/-test-/bignum/str2big.c (revision 42805) +++ ext/-test-/bignum/str2big.c (revision 42806) @@ -19,10 +19,21 @@ str2big_karatsuba(VALUE str, VALUE vbase https://github.com/ruby/ruby/blob/trunk/ext/-test-/bignum/str2big.c#L19 return rb_str2big_karatsuba(str, NUM2INT(vbase), RTEST(badcheck)); } +#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H) +static VALUE +str2big_gmp(VALUE str, VALUE vbase, VALUE badcheck) +{ + return rb_str2big_gmp(str, NUM2INT(vbase), RTEST(badcheck)); +} +#else +#define str2big_gmp rb_f_notimplement +#endif + void Init_str2big(VALUE klass) { rb_define_method(rb_cString, "str2big_poweroftwo", str2big_poweroftwo, 2); rb_define_method(rb_cString, "str2big_normal", str2big_normal, 2); rb_define_method(rb_cString, "str2big_karatsuba", str2big_karatsuba, 2); + rb_define_method(rb_cString, "str2big_gmp", str2big_gmp, 2); } Index: internal.h =================================================================== --- internal.h (revision 42805) +++ internal.h (revision 42806) @@ -653,6 +653,7 @@ VALUE rb_str2big_karatsuba(VALUE arg, in https://github.com/ruby/ruby/blob/trunk/internal.h#L653 #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); +VALUE rb_str2big_gmp(VALUE arg, int base, int badcheck); #endif /* file.c */ Index: bignum.c =================================================================== --- bignum.c (revision 42805) +++ bignum.c (revision 42806) @@ -136,6 +136,7 @@ STATIC_ASSERT(sizeof_long_and_sizeof_bdi https://github.com/ruby/ruby/blob/trunk/bignum.c#L136 #define TOOM3_MUL_DIGITS 150 #define GMP_BIG2STR_DIGITS 20 +#define GMP_STR2BIG_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); @@ -3781,6 +3782,50 @@ str2big_karatsuba( https://github.com/ruby/ruby/blob/trunk/bignum.c#L3782 return z; } +#ifdef USE_GMP +static VALUE +str2big_gmp( + int sign, + const char *digits_start, + const char *digits_end, + size_t num_digits, + size_t num_bdigits, + int base) +{ + const size_t nails = (sizeof(BDIGIT)-SIZEOF_BDIGITS)*CHAR_BIT; + char *buf, *p; + const char *q; + VALUE tmps; + mpz_t mz; + VALUE z; + BDIGIT *zds; + size_t zn, count; + + buf = ALLOCV_N(char, tmps, num_digits+1); + p = buf; + for (q = digits_start; q < digits_end; q++) { + if (conv_digit(*q) < 0) + continue; + *p++ = *q; + } + *p = '\0'; + + mpz_init(mz); + mpz_set_str(mz, buf, base); + zn = num_bdigits; + z = bignew(zn, sign); + zds = BDIGITS(z); + mpz_export(BDIGITS(z), &count, -1, sizeof(BDIGIT), 0, nails, mz); + BDIGITS_ZERO(zds+count, zn-count); + mpz_clear(mz); + + if (tmps) + ALLOCV_END(tmps); + + return z; +} +#endif + VALUE rb_cstr_to_inum(const char *str, int base, int badcheck) { @@ -3927,6 +3972,13 @@ rb_cstr_to_inum(const char *str, int bas https://github.com/ruby/ruby/blob/trunk/bignum.c#L3972 maxpow_in_bdigit_dbl(base, &digits_per_bdigits_dbl); num_bdigits = roomof(num_digits, digits_per_bdigits_dbl)*2; +#ifdef USE_GMP + if (GMP_STR2BIG_DIGITS < num_bdigits) { + z = str2big_gmp(sign, digits_start, digits_end, num_digits, + num_bdigits, base); + } + else +#endif if (num_bdigits < KARATSUBA_MUL_DIGITS) { z = str2big_normal(sign, digits_start, digits_end, num_bdigits, base); @@ -4083,6 +4135,46 @@ rb_str2big_karatsuba(VALUE arg, int base https://github.com/ruby/ruby/blob/trunk/bignum.c#L4135 return bignorm(z); } +#ifdef USE_GMP +VALUE +rb_str2big_gmp(VALUE arg, int base, int badcheck) +{ + int positive_p = 1; + const char *s, *str; + const char *digits_start, *digits_end; + size_t num_digits; + size_t len; + VALUE z; + + int digits_per_bdigits_dbl; + size_t num_bdigits; + + if (base < 2 || 36 < base) { + rb_raise(rb_eArgError, "invalid radix %d", base); + } + + rb_must_asciicompat(arg); + s = str = StringValueCStr(arg); + if (*str == '-') { + str++; + positive_p = 0; + } + + digits_start = str; + str2big_scan_digits(s, str, base, badcheck, &num_digits, &len); + digits_end = digits_start + len; + + maxpow_in_bdigit_dbl(base, &digits_per_bdigits_dbl); + num_bdigits = roomof(num_digits, digits_per_bdigits_dbl)*2; + + z = str2big_gmp(positive_p, digits_start, digits_end, num_digits, num_bdigits, base); + + RB_GC_GUARD(arg); + + return bignorm(z); +} +#endif + #if HAVE_LONG_LONG static VALUE Index: test/-ext-/bignum/test_str2big.rb =================================================================== --- test/-ext-/bignum/test_str2big.rb (revision 42805) +++ test/-ext-/bignum/test_str2big.rb (revision 42806) @@ -26,5 +26,12 @@ class TestBignum < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/-ext-/bignum/test_str2big.rb#L26 assert_equal(n, s.str2big_karatsuba(10, true)) end + def test_str2big_gmp + s = "1" + "0" * 1000 + n = 10 ** 1000 + assert_equal(n, s.str2big_gmp(10, true)) + rescue NotImplementedError + end + end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/