mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42806 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
1b126277ed
commit
2583689340
5 changed files with 120 additions and 0 deletions
|
@ -1,3 +1,12 @@
|
|||
Tue Sep 3 20:12:46 2013 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* 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@ruby-lang.org>
|
||||
|
||||
* ext/win32/lib/win32/registry.rb (Win32::Registry#values): added.
|
||||
|
|
92
bignum.c
92
bignum.c
|
@ -136,6 +136,7 @@ STATIC_ASSERT(sizeof_long_and_sizeof_bdigit, SIZEOF_BDIGITS % SIZEOF_LONG == 0);
|
|||
#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(
|
|||
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 base, int badcheck)
|
|||
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, int badcheck)
|
|||
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
|
||||
|
|
|
@ -19,10 +19,21 @@ str2big_karatsuba(VALUE str, VALUE vbase, VALUE badcheck)
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -653,6 +653,7 @@ VALUE rb_str2big_karatsuba(VALUE arg, int base, int badcheck);
|
|||
#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 */
|
||||
|
|
|
@ -26,5 +26,12 @@ class TestBignum < Test::Unit::TestCase
|
|||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue