summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--bignum.c111
-rw-r--r--ext/-test-/bignum/depend1
-rw-r--r--ext/-test-/bignum/str2big.c28
-rw-r--r--internal.h3
-rw-r--r--test/-ext-/bignum/test_str2big.rb30
6 files changed, 189 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index fa43db1..44e7994 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+Tue Sep 3 12:45:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_str2big_poweroftwo): New function.
+ (rb_str2big_normal): Ditto.
+ (rb_str2big_karatsuba): Ditto.
+
+ * internal.h (rb_str2big_poweroftwo): Declared.
+ (rb_str2big_normal): Ditto.
+ (rb_str2big_karatsuba): Ditto.
+
+ * ext/-test-/bignum/str2big.c: New file.
+
+ * test/-ext-/bignum/test_str2big.rb: New file.
+
+ * ext/-test-/bignum/depend: Add the dependency for str2big.c.
+
Tue Sep 3 12:09:08 2013 Tanaka Akira <akr@fsij.org>
* process.c (rb_clock_gettime): Support times() based monotonic clock.
diff --git a/bignum.c b/bignum.c
index 941e803..ec9cbfb 100644
--- a/bignum.c
+++ b/bignum.c
@@ -3972,6 +3972,117 @@ rb_str_to_inum(VALUE str, int base, int badcheck)
return ret;
}
+VALUE
+rb_str2big_poweroftwo(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;
+
+ if (base < 2 || 36 < base || !POW2_P(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;
+
+ z = str2big_poweroftwo(positive_p, digits_start, digits_end, num_digits,
+ bit_length(base-1));
+
+ RB_GC_GUARD(arg);
+
+ return bignorm(z);
+}
+
+VALUE
+rb_str2big_normal(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_normal(positive_p, digits_start, digits_end,
+ num_bdigits, base);
+
+ RB_GC_GUARD(arg);
+
+ return bignorm(z);
+}
+
+VALUE
+rb_str2big_karatsuba(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_karatsuba(positive_p, digits_start, digits_end, num_digits,
+ num_bdigits, digits_per_bdigits_dbl, base);
+
+ RB_GC_GUARD(arg);
+
+ return bignorm(z);
+}
+
#if HAVE_LONG_LONG
static VALUE
diff --git a/ext/-test-/bignum/depend b/ext/-test-/bignum/depend
index cac4d52..4634ecf 100644
--- a/ext/-test-/bignum/depend
+++ b/ext/-test-/bignum/depend
@@ -3,3 +3,4 @@ $(OBJS): $(HDRS) $(ruby_headers)
intpack.o: intpack.c $(top_srcdir)/internal.h
mul.o: mul.c $(top_srcdir)/internal.h
big2str.o: big2str.c $(top_srcdir)/internal.h
+str2big.o: big2str.c $(top_srcdir)/internal.h
diff --git a/ext/-test-/bignum/str2big.c b/ext/-test-/bignum/str2big.c
new file mode 100644
index 0000000..b6492fa
--- /dev/null
+++ b/ext/-test-/bignum/str2big.c
@@ -0,0 +1,28 @@
+#include "ruby.h"
+#include "internal.h"
+
+static VALUE
+str2big_poweroftwo(VALUE str, VALUE vbase, VALUE badcheck)
+{
+ return rb_str2big_poweroftwo(str, NUM2INT(vbase), RTEST(badcheck));
+}
+
+static VALUE
+str2big_normal(VALUE str, VALUE vbase, VALUE badcheck)
+{
+ return rb_str2big_normal(str, NUM2INT(vbase), RTEST(badcheck));
+}
+
+static VALUE
+str2big_karatsuba(VALUE str, VALUE vbase, VALUE badcheck)
+{
+ return rb_str2big_karatsuba(str, NUM2INT(vbase), RTEST(badcheck));
+}
+
+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);
+}
diff --git a/internal.h b/internal.h
index 9d7ce97..bf5446b 100644
--- a/internal.h
+++ b/internal.h
@@ -647,6 +647,9 @@ VALUE rb_big_mul_toom3(VALUE x, VALUE y);
VALUE rb_big_sq_fast(VALUE x);
VALUE rb_big2str_poweroftwo(VALUE x, int base);
VALUE rb_big2str_generic(VALUE x, int base);
+VALUE rb_str2big_poweroftwo(VALUE arg, int base, int badcheck);
+VALUE rb_str2big_normal(VALUE arg, int base, int badcheck);
+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);
diff --git a/test/-ext-/bignum/test_str2big.rb b/test/-ext-/bignum/test_str2big.rb
new file mode 100644
index 0000000..ac55c78
--- /dev/null
+++ b/test/-ext-/bignum/test_str2big.rb
@@ -0,0 +1,30 @@
+require 'test/unit'
+require "-test-/bignum"
+
+class TestBignum < Test::Unit::TestCase
+ class TestStr2big < Test::Unit::TestCase
+
+ SIZEOF_BDIGITS = Bignum::SIZEOF_BDIGITS
+ BITSPERDIG = Bignum::BITSPERDIG
+ BDIGMAX = (1 << BITSPERDIG) - 1
+
+ def test_str2big_poweroftwo
+ s = "1" + "0" * 1000
+ n = 16 ** 1000
+ assert_equal(n, s.str2big_poweroftwo(16, true))
+ end
+
+ def test_str2big_normal
+ s = "1" + "0" * 1000
+ n = 10 ** 1000
+ assert_equal(n, s.str2big_normal(10, true))
+ end
+
+ def test_str2big_karatsuba
+ s = "1" + "0" * 1000
+ n = 10 ** 1000
+ assert_equal(n, s.str2big_karatsuba(10, true))
+ end
+
+ end
+end