[#31320] Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...>

-----BEGIN PGP SIGNED MESSAGE-----

124 messages 2007/08/01
[#31321] Re: Import RubyGems to Ruby 1.9 — Nobuyoshi Nakada <nobu@...> 2007/08/01

なかだです。

[#31329] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/08/01

-----BEGIN PGP SIGNED MESSAGE-----

[#31918] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/09/30

-----BEGIN PGP SIGNED MESSAGE-----

[#31970] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/08

-----BEGIN PGP SIGNED MESSAGE-----

[#32023] Re: Import RubyGems to Ruby 1.9 — Yukihiro Matsumoto <matz@...> 2007/10/11

まつもと ゆきひろです

[#32062] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/15

-----BEGIN PGP SIGNED MESSAGE-----

[#32066] Re: Import RubyGems to Ruby 1.9 — Yukihiro Matsumoto <matz@...> 2007/10/15

まつもと ゆきひろです

[#32068] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/15

-----BEGIN PGP SIGNED MESSAGE-----

[#32069] Re: Import RubyGems to Ruby 1.9 — Yukihiro Matsumoto <matz@...> 2007/10/15

まつもと ゆきひろです

[#32070] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/15

-----BEGIN PGP SIGNED MESSAGE-----

[#32073] Re: Import RubyGems to Ruby 1.9 — Yukihiro Matsumoto <matz@...> 2007/10/15

まつもと ゆきひろです

[#32079] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/16

-----BEGIN PGP SIGNED MESSAGE-----

[#32080] Re: Import RubyGems to Ruby 1.9 — Yukihiro Matsumoto <matz@...> 2007/10/16

まつもと ゆきひろです

[#32132] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/23

-----BEGIN PGP SIGNED MESSAGE-----

[#32104] Re: Import RubyGems to Ruby 1.9 — akira yamada <akira@...> 2007/10/20

Tuesday 16 October 2007 14:09:13 に NAKAMURA, Hiroshi さんは書きました:

[#32109] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/20

-----BEGIN PGP SIGNED MESSAGE-----

[#32081] Re: Import RubyGems to Ruby 1.9 — Takahiro Kambe <taca@...> 2007/10/16

In message <471447D5.5050902@sarion.co.jp>

[#32087] Re: Import RubyGems to Ruby 1.9 — "Akinori MUSHA" <knu@...> 2007/10/17

 Rubygems は、基本的に他のパッケージシステムから包みやすい作り

[#31332] Re: Import RubyGems to Ruby 1.9 — Tadayoshi Funaba <tadf@...> 2007/08/01

> ちなみに「ruby/1.9.1の標準添付からどのライブラリを外すか?」という議論も

[#31858] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/09/25

-----BEGIN PGP SIGNED MESSAGE-----

[#31872] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/09/27

-----BEGIN PGP SIGNED MESSAGE-----

[#31905] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/09/29

-----BEGIN PGP SIGNED MESSAGE-----

[#31906] Re: Import RubyGems to Ruby 1.9 — Yukihiro Matsumoto <matz@...> 2007/09/29

まつもと ゆきひろです

[#31910] Re: Import RubyGems to Ruby 1.9 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/09/30

-----BEGIN PGP SIGNED MESSAGE-----

[#31920] Re: Import RubyGems to Ruby 1.9 — Yukihiro Matsumoto <matz@...> 2007/09/30

まつもと ゆきひろです

[#31323] Bignum#to_s の Karatsuba 基数変換による高速化 — "Kenta Murata" <muraken@...>

むらけんです.

16 messages 2007/08/01
[#31326] Re: Bignum#to_s の Karatsuba 基数変換による高速化 — Yukihiro Matsumoto <matz@...> 2007/08/01

まつもと ゆきひろです

[#31327] Re: Bignum#to_s の Karatsuba 基数変換による高速化 — "Kenta Murata" <muraken@...> 2007/08/01

むらけんです.

[#31328] Re: Bignum#to_s の Karatsuba 基数変換による高速化 — Yukihiro Matsumoto <matz@...> 2007/08/01

まつもと ゆきひろです

[#31525] いくつかのバグ報告と提案(5点) — eklerni <eklerni@...>

From:eklerni

13 messages 2007/08/20

[#31539] strtod の精度 — Satoshi Nakagawa <snakagawa@...>

中川といいます。

27 messages 2007/08/20
[#31542] Re: strtod の精度 — Yukihiro Matsumoto <matz@...> 2007/08/20

まつもと ゆきひろです

[ruby-dev:31327] Re: Bignum#to_s の Karatsuba 基数変換による高速化

From: "Kenta Murata" <muraken@...>
Date: 2007-08-01 09:37:16 UTC
List: ruby-dev #31327
むらけんです.

# 私のところに ruby-dev:31312 が届いてないのが不思議・・・

On 8/1/07, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:
> まつもと ゆきひろです
> ちょうど[ruby-dev:31312]を取り込もうと思っていた矢先だったの
> ですが、どっちがいいですかねえ。

同じ条件で処理時間を計測して,短い方を採用したらいいと思いました.
そこで,添付のようなパッチと,ベンチマークプログラムで計測したところ
以下のようになりました.

$ ./ruby -I lib karatsuba.rb
Rehearsal --------------------------------------------------
original         2.410000   0.000000   2.410000 (  9.625259)
ruby-dev:31312   2.420000   0.000000   2.420000 (  9.635740)
ruby-dev:31323   1.740000   0.000000   1.740000 (  6.842046)
----------------------------------------- total: 6.570000sec

                    user     system      total        real
original         2.420000   0.000000   2.420000 (  9.931306)
ruby-dev:31312   2.420000   0.000000   2.420000 (  9.627448)
ruby-dev:31323   1.740000   0.000000   1.740000 (  6.842890)

なぜか ruby-dev:31312 が,オリジナルと比較して早くなってないのですが,
ベンチマークプログラムが悪いのでしょうか・・・
単純に[ruby-dev:31312] が速くなる条件と,私の [ruby-dev:31323] が
速くなる条件が違うという理解で良いものかどうか.

加えて,[ruby-dev:31323] で添付した私のパッチはバグがある状態のものでした.
正しくは,

+VALUE
+rb_big2str_karatsuba(VALUE x, VALUE base)
+{
+    return rb_big2str0_karatsuba(x, FIX2INT(base), Qtrue);
+}
+

この部分を以下のように修正してください.

+VALUE
+rb_big2str_karatsuba(VALUE x, int base)
+{
+    return rb_big2str0_karatsuba(x, base, Qtrue);
+}

> あと、Karatsubaといえばかけ算
> の高速化についても(アルゴリズムが理解できず)ほったらかしだっ
> たんですよねえ。

今すぐというわけにはいかないのですが,こちらも手をつけようと思っています.
Ruby にはできるだけ速くなってもらいたいです :)

--
Kenta Murata
OpenPGP FP = FA26 35D7 4F98 3498 0810 E0D5 F213 966F E9EB 0BCC

Attachments (2)

bignum_31312_31323.patch (13.1 KB, text/x-diff)
Index: bignum.c
===================================================================
--- bignum.c	(revision 12859)
+++ bignum.c	(working copy)
@@ -19,6 +19,8 @@
 #include <ieeefp.h>
 #endif
 
+#include <st.h>
+
 VALUE rb_cBignum;
 
 #if defined __MINGW32__
@@ -727,12 +729,467 @@
     return ss;
 }
 
+#define MAX_POWER_CACHE_ENTRIES 64
+
+struct power_cache_data
+{
+    VALUE power;
+    long  magic;
+};
+
+struct power_cache_entry
+{
+    st_table* cache;
+    long      len;
+};
+
+struct power_cache
+{
+    struct power_cache_entry entries[35];
+};
+
+static int
+mark_cache_entry(long n1, struct power_cache_data* data, void* _)
+{
+    rb_gc_mark(data->power);
+    return ST_CONTINUE;
+}
+
+static void
+power_cache_mark(struct power_cache* pc)
+{
+    int i;
+    for (i = 0; i < 35; ++i)
+        st_foreach(pc->entries[i].cache, mark_cache_entry, 0);
+}
+
+static int
+free_cache_entry(long n1, struct power_cache_data* data, void* _)
+{
+    if (data != 0)
+        free(data);
+    return ST_DELETE;
+}
+
+static void
+power_cache_free(struct power_cache* pc)
+{
+    int i;
+    for (i = 0; i < 35; ++i) {
+        st_foreach(pc->entries[i].cache, free_cache_entry, 0);
+        st_free_table(pc->entries[i].cache);
+    }
+    free(pc);
+}
+
+static VALUE big2str_power_cache = 0;
+
+static void
+power_cache_init(void)
+{
+    struct power_cache* pc;
+    int i;
+
+    big2str_power_cache = Data_Make_Struct(
+      rb_cData, struct power_cache, power_cache_mark, power_cache_free, pc);
+    rb_global_variable(&big2str_power_cache);
+    for (i = 0; i < 35; i++) {
+        pc->entries[i].cache = st_init_numtable();
+        pc->entries[i].len = 0;
+    }
+}
+
+struct power_cache_find_to_remove_data
+{
+    long n1;
+    long max_magic;
+};
+
+static int
+power_cache_find_to_remove(long n1, struct power_cache_data* pcd,
+                           struct power_cache_find_to_remove_data* data)
+{
+    if (pcd->magic > data->max_magic) {
+        data->n1 = n1;
+        data->max_magic = pcd->magic++;
+    }
+    return ST_CONTINUE;
+}
+
+static VALUE
+power_cache_lookup(base, n1)
+    int base;
+    long n1;
+{
+    struct power_cache* pc;
+    struct power_cache_data* pcd = 0;
+
+    if (big2str_power_cache == 0) power_cache_init();
+    Data_Get_Struct(big2str_power_cache, struct power_cache, pc);
+    if (pc->entries[base - 2].len == 0 ||
+        !st_lookup(pc->entries[base - 2].cache, n1, (st_data_t*)&pcd))
+        return Qnil;
+    return pcd->power;
+}
+
+static void
+power_cache_insert(base, n1, power)
+    int base;
+    long n1;
+    VALUE power;
+{
+    struct power_cache* pc;
+    struct power_cache_data* pcd;
+
+    Data_Get_Struct(big2str_power_cache, struct power_cache, pc);
+    if (pc->entries[base - 2].len == MAX_POWER_CACHE_ENTRIES) {
+        struct power_cache_find_to_remove_data data = { 0, 0 };
+        st_foreach(pc->entries[base - 2].cache,
+                   power_cache_find_to_remove, (st_data_t)&data);
+        st_delete(pc->entries[base - 2].cache, &data.n1, 0);
+        pc->entries[base - 2].len--;
+    }
+
+    pcd = ALLOC(struct power_cache_data);
+    pcd->power = power;
+    pcd->magic = 0;
+    st_insert(pc->entries[base - 2].cache, n1, (st_data_t)pcd);
+    pc->entries[base - 2].len++;
+}
+
+static VALUE
+power_cache_get_power(base, n1)
+    int base;
+    long n1;
+{
+    VALUE power = power_cache_lookup(base, n1);
+    if (NIL_P(power)) {
+        power = rb_big_pow(rb_int2big(base), LONG2NUM(n1));
+        power_cache_insert(base, n1, power);
+    }
+    return power;
+}
+
+/* big2str_karatsuba_find_n1
+ *
+ * Let a natural number x is given by:
+ * x = 2^0 * x_0 + 2^1 * x_1 + ... + 2^(B*n_0 - 1) * x_{B*n_0 - 1},
+ * where B is BITSPERDIG (i.e. BDIGITS*CHAR_BIT) and n_0 is
+ * RBIGNUM(x)->len.
+ *
+ * Now, we assume n_1 = min_n \{ n | 2^(B*n_0/2) <= b_1^(n_1) \}, so
+ * it is realized that 2^(B*n_0) <= {b_1}^{2*n_1}, where b_1 is a
+ * given radix number. And then, we have n_1 <= (B*n_0) /
+ * (2*log_2(b_1)), therefore n_1 is given by ceil((B*n_0) /
+ * (2*log_2(b_1))).
+ */
+static long
+big2str_karatsuba_find_n1(VALUE x, int base)
+{
+    static const double log_2[] = {
+        1.0,              1.58496250072116, 2.0,
+        2.32192809488736, 2.584962500721,   2.58496250072116,
+        2.8073549220576,  3.0,              3.16992500144231,
+        3.32192809488736, 3.4594316186373,  3.58496250072116,
+        3.70043971814109, 3.8073549220576,  3.90689059560852,
+        4.0,              4.08746284125034, 4.16992500144231,
+        4.24792751344359, 4.32192809488736, 4.39231742277876,
+        4.4594316186373,  4.52356195605701, 4.58496250072116,
+        4.64385618977472, 4.70043971814109, 4.75488750216347,
+        4.8073549220576,  4.85798099512757, 4.90689059560852,
+        4.95419631038688, 5.0,              5.04439411935845,
+        5.08746284125034, 5.12928301694497, 5.16992500144231
+    };
+    long bits;
+
+    if (base < 2 && 36 < base)
+      rb_bug("illegal radix %d", base);
+
+    if (FIXNUM_P(x)) {
+        bits = (SIZEOF_LONG*CHAR_BIT - 1)/2 + 1;
+    }
+    else if (BIGZEROP(x)) {
+        return 0;
+    }
+    else {
+        bits = BITSPERDIG*RBIGNUM(x)->len;
+    }
+
+    return (long)(bits/(2*log_2[base - 2]) + 1);
+}
+
+static long
+big2str_karatsuba_without_sign(x, base, ptr, n1)
+    VALUE x;
+    int base;
+    char* ptr;
+    long n1;
+{
+    long len = 2*n1;
+    VALUE b, qr;
+
+    if (FIXNUM_P(x)) {
+        VALUE str = rb_fix2str(x, base);
+        memset(ptr, '0', len - RSTRING(str)->len);
+        MEMCPY(ptr + len - RSTRING(str)->len, RSTRING(str)->ptr,
+               char, RSTRING(str)->len);
+        return;
+    }
+    if (BIGZEROP(x)) {
+        memset(ptr, '0', len);
+        return;
+    }
+
+    if (n1 % 2 == 1) ++n1;
+    b = power_cache_get_power(base, n1);
+    qr = rb_big_divmod(x, b);
+    big2str_karatsuba_without_sign(
+        RARRAY(qr)->ptr[0], base, ptr,              (len - n1)/2);
+    big2str_karatsuba_without_sign(
+        RARRAY(qr)->ptr[1], base, ptr + (len - n1), n1/2);
+}
+
 VALUE
+rb_big2str0_karatsuba(x, base, trim)
+    VALUE x;
+    int base;
+    int trim;
+{
+    VALUE ss, xx;
+    long n1;
+
+    if (FIXNUM_P(x)) {
+        return rb_fix2str(x, base);
+    }
+    if (BIGZEROP(x)) {
+        return rb_str_new2("0");
+    }
+
+    if (base < 2 && 36 < base)
+        rb_raise(rb_eArgError, "illegal radix %d", base);
+
+    xx = rb_big_clone(x);
+    n1 = big2str_karatsuba_find_n1(xx, base);
+    ss = rb_str_new(0, 2*n1 + 1); /* plus one for sign */
+    RSTRING(ss)->ptr[0] = RBIGNUM(xx)->sign ? '+' : '-';
+    RBIGNUM(xx)->sign = 1;
+
+    big2str_karatsuba_without_sign(
+        xx, base, RSTRING(ss)->ptr + 1, n1);
+    if (trim) {
+        int i = 1;
+        while (RSTRING(ss)->ptr[i] == '0') ++i;
+        if (RBIGNUM(x)->sign) {
+            MEMMOVE(RSTRING(ss)->ptr, RSTRING(ss)->ptr + i,
+                    char, RSTRING(ss)->len - i); /* plus one for '\0' */
+        }
+        else {
+            MEMMOVE(RSTRING(ss)->ptr + 1, RSTRING(ss)->ptr + i,
+                    char, RSTRING(ss)->len - i); /* plus one for '\0' */
+        }
+        RSTRING(ss)->len -= i - !RBIGNUM(x)->sign;
+    }
+    RSTRING(ss)->ptr[RSTRING(ss)->len] = '\0';
+
+    return ss;
+}
+
+static inline int
+big2str_normal(VALUE x, long j, int base, int hbase, char *s, int trim)
+{
+    long i = RBIGNUM(x)->len;
+    BDIGIT *ds = BDIGITS(x);
+
+    while (i && j > 1) {
+       long k = i;
+       BDIGIT_DBL num = 0;
+
+       while (k--) {
+           num = BIGUP(num) + ds[k];
+           ds[k] = (BDIGIT)(num / hbase);
+           num %= hbase;
+       }
+       if (trim && ds[i-1] == 0) i--;
+       k = SIZEOF_BDIGITS;
+       while (k--) {
+           s[--j] = ruby_digitmap[num % base];
+           num /= base;
+           if (!trim && j < 1) break;
+           if (trim && i == 0 && num == 0) break;
+       }
+    }
+    return j;
+}
+
+#define KARATSUBA_DIGITS 1024
+static VALUE big2str_table[37][16];
+
+static VALUE bigsqr(VALUE x);
+static void bigdivmod(VALUE x, VALUE y, VALUE *divp, VALUE *modp);
+
+static inline int
+big2str_karatsuba_31312(VALUE x, int n, int base, int hbase, char *s, int trim)
+{
+    long i, j, k, bs_len, sign = RBIGNUM(x)->sign;
+    volatile VALUE t = big2str_table[base][0], t2;
+    VALUE *as, *bs, q, r;
+
+    j = RBIGNUM(t)->len;
+    for (i=0; j <= RBIGNUM(x)->len; i++) j *= 2;
+
+    as = ALLOCA_N(VALUE, i);
+
+    for (i=0,j=1; ; i++,j*=2) {
+       as[i] = t;
+       if(big2str_table[base][i + 1]) {
+           t2 = big2str_table[base][i + 1];
+       }
+       else {
+           t2 = bigsqr(t);
+           if(i + 1 < 16) {
+               big2str_table[base][i + 1] = t2;
+               rb_global_variable(&big2str_table[base][i + 1]);
+           }
+       }
+       if(RBIGNUM(x)->len < RBIGNUM(t2)->len) break;
+       t = t2;
+    }
+
+    bs_len = j * 2;
+    bs = ALLOCA_N(VALUE, bs_len);
+    bs[0] = x;
+    RBIGNUM(x)->sign = 1;
+    for (; j>0; i--, j/=2) {
+       for (k=0; k<bs_len; k+=j*2) {
+           bigdivmod(bs[k], as[i], &q, &r);
+           bs[k] = q;
+           bs[k + j] = r;
+       }
+    }
+    RBIGNUM(x)->sign = sign;
+
+    j = 0;
+    while(RBIGNUM(bs[j])->len == 1 && BDIGITS(bs[j])[0] == 0) j++;
+    for (i=bs_len-1; i>j; i--) {
+       k = big2str_normal(
+           bs[i], KARATSUBA_DIGITS, base, hbase,
+           s + n - KARATSUBA_DIGITS, Qfalse);
+       n -= KARATSUBA_DIGITS - k;
+    }
+    n = big2str_normal(bs[j], n, base, hbase, s, trim);
+
+    return n;
+}
+
+VALUE
+rb_big2str0_31312(VALUE x, int base, int trim)
+{
+    volatile VALUE t;
+    long i, j, hbase;
+    VALUE ss;
+    char *s;
+
+    if (FIXNUM_P(x)) {
+	return rb_fix2str(x, base);
+    }
+    i = RBIGNUM(x)->len;
+    if (BIGZEROP(x)) {
+	return rb_str_new2("0");
+    }
+    j = SIZEOF_BDIGITS*CHAR_BIT*i;
+    switch (base) {
+      case 2: break;
+      case 3:
+	j = j * 53L / 84 + 1;
+	break;
+      case 4: case 5: case 6: case 7:
+	j = (j + 1) / 2;
+	break;
+      case 8: case 9:
+	j = (j + 2) / 3;
+	break;
+      case 10: case 11: case 12: case 13: case 14: case 15:
+	j = j * 28L / 93 + 1;
+	break;
+      case 16: case 17: case 18: case 19: case 20: case 21:
+      case 22: case 23: case 24: case 25: case 26: case 27:
+      case 28: case 29: case 30: case 31:
+	j = (j + 3) / 4;
+	break;
+      case 32: case 33: case 34: case 35: case 36:
+	j = (j + 4) / 5;
+	break;
+      default:
+	rb_raise(rb_eArgError, "illegal radix %d", base);
+	break;
+    }
+    j++;			/* space for sign */
+
+    hbase = base * base;
+#if SIZEOF_BDIGITS > 2
+    hbase *= hbase;
+#endif
+
+    t = rb_big_clone(x);
+    ss = rb_str_new(0, j+1);
+    s = RSTRING(ss)->ptr;
+
+    s[0] = RBIGNUM(x)->sign ? '+' : '-';
+    if (RBIGNUM(x)->len > RBIGNUM(big2str_table[base][0])->len * 4) {
+       j = big2str_karatsuba_31312(t, j, base, hbase, s, trim);
+    }
+    else {
+       j = big2str_normal(t, j, base, hbase, s, trim);
+    }
+    if (trim) {while (s[j] == '0') j++;}
+    i = RSTRING(ss)->len - j;
+    if (RBIGNUM(x)->sign) {
+	memmove(s, s+j, i);
+	RSTRING(ss)->len = i-1;
+    }
+    else {
+	memmove(s+1, s+j, i);
+	RSTRING(ss)->len = i;
+    }
+    s[RSTRING(ss)->len] = '\0';
+
+    return ss;
+}
+
+static void
+init_big2str_table(void)
+{
+    int i, j;
+    VALUE v;
+
+    for (i=0; i<37; i++) {
+       v = rb_big_pow(rb_int2big(i), INT2FIX(KARATSUBA_DIGITS));
+       big2str_table[i][0] = v;
+       rb_global_variable(&big2str_table[i][0]);
+       for (j=1; j<16; j++) {
+           big2str_table[i][j] = Qfalse;
+       }
+    }
+}
+
+VALUE
 rb_big2str(VALUE x, int base)
 {
     return rb_big2str0(x, base, Qtrue);
 }
 
+VALUE
+rb_big2str_karatsuba(VALUE x, int base)
+{
+    return rb_big2str0_karatsuba(x, base, Qtrue);
+}
+
+VALUE
+rb_big2str_31312(VALUE x, int base)
+{
+    return rb_big2str0_31312(x, base, Qtrue);
+}
+
 /*
  *  call-seq:
  *     big.to_s(base=10)   =>  string
@@ -748,7 +1205,7 @@
  */
 
 static VALUE
-rb_big_to_s(argc, argv, x)
+rb_big_to_s_orig(argc, argv, x)
     int argc;
     VALUE *argv;
     VALUE x;
@@ -762,6 +1219,36 @@
     return rb_big2str(x, base);
 }
 
+static VALUE
+rb_big_to_s(argc, argv, x)
+    int argc;
+    VALUE *argv;
+    VALUE x;
+{
+    VALUE b;
+    int base;
+
+    rb_scan_args(argc, argv, "01", &b);
+    if (argc == 0) base = 10;
+    else base = NUM2INT(b);
+    return rb_big2str_karatsuba(x, base);
+}
+
+static VALUE
+rb_big_to_s_31312(argc, argv, x)
+    int argc;
+    VALUE *argv;
+    VALUE x;
+{
+    VALUE b;
+    int base;
+
+    rb_scan_args(argc, argv, "01", &b);
+    if (argc == 0) base = 10;
+    else base = NUM2INT(b);
+    return rb_big2str_31312(x, base);
+}
+
 static unsigned long
 big2ulong(x, type)
     VALUE x;
@@ -2314,6 +2801,8 @@
 {
     rb_cBignum = rb_define_class("Bignum", rb_cInteger);
 
+    rb_define_method(rb_cBignum, "to_s_orig", rb_big_to_s_orig, -1);
+    rb_define_method(rb_cBignum, "to_s_31312", rb_big_to_s_31312, -1);
     rb_define_method(rb_cBignum, "to_s", rb_big_to_s, -1);
     rb_define_method(rb_cBignum, "coerce", rb_big_coerce, 1);
     rb_define_method(rb_cBignum, "-@", rb_big_uminus, 0);
@@ -2344,4 +2833,6 @@
     rb_define_method(rb_cBignum, "to_f", rb_big_to_f, 0);
     rb_define_method(rb_cBignum, "abs", rb_big_abs, 0);
     rb_define_method(rb_cBignum, "size", rb_big_size, 0);
+
+    init_big2str_table();
 }
karatsuba.rb (373 Bytes, text/x-ruby)
require 'benchmark'

$values = (1..100).to_a.collect{ rand(10**1024 - 1) }

def main
  $values.each{|v| (2..36).each{|b| yield(v, b) }}
end

Benchmark.bmbm do |x|
  x.report('original') do
    main {|v, b| v.to_s_orig(b) }
  end
  x.report('ruby-dev:31312') do
    main {|v, b| v.to_s_31312(b) }
  end
  x.report('ruby-dev:31323') do
    main {|v, b| v.to_s(b) }
  end
end

In This Thread