Optimize small bignum space

e$B;W$$N)$C$F!">.$5$$e(B Bignum e$B$re(B RBignum
e$B$K5M$a$k$h$&$K$7$F$_$^e(B
e$B$7$?!#$I$&$G$7$g$&$+!#e(B

3 word e$B;H$($k$N$G!“e(B32bit e$B$Ge(B 296 e$B$"$?$j$^$GF~$j$^$9!#e(B
(64bit e$B$J$ie(B 2
192 e$B$”$?$j$^$Ge(B)

./ruby -e ‘a = []; 1000000.times { a << 0xfffffffffffffffffffffffe+1 }’
e$B$H$$$&?M9)E*$J$b$N$G$"$l$PH>J,6a$/%a%b%j>CHq$,8:$i$;$^$9!#$de(B
e$B$O$je(B malloc e$B<+BN$rL5$/$9$H8z$-$^$9$M!#e(B

e$B$b$A$m$s!“8=<B$K$Oe(B 231 e$B$+$ie(B 296 e$B$”$?$j$Ne(B Bignum
e$B$r$I$N$/e(B
e$B$i$$;H$&$+$,LdBj$K$J$j$^$9$,!"$$$^$N$^$^$@$He(B 32bit e$B$JCM$N7We(B
e$B;;$r$9$k$H$-$K%a%b%j$NL5BL$J5$J,$,$9$k$N$G!"$I$s$J$b$N$G$7$ge(B
e$B$&$+!#e(B

Index: .gdbinit

— .gdbinit (e$B%j%S%8%g%se(B 13324)
+++ .gdbinit (e$B:n6H%3%T!<e(B)
@@ -95,9 +95,17 @@
else
if ($flags & 0x1f) == 0x0d
printf "T_BIGNUM: sign=%d len=%d ", \

  •  ((struct RBignum*)$arg0)->sign, ((struct RBignum*)$arg0)->len
    
  •  (($flags & RUBY_FL_USER1) != 0), \
    
  •  (($flags & RUBY_FL_USER2) ? \
    
  •   ($flags & (RUBY_FL_USER5|RUBY_FL_USER4|RUBY_FL_USER3)) >> 
    

(RUBY_FL_USHIFT+3) : \

  •   ((struct RBignum*)$arg0)->as.heap.len)
    
  • if $flags & RUBY_FL_USER2
  •  printf "(embed) "
    
  • end
    print (struct RBignum *)$arg0
  • x/xw ((struct RBignum*)$arg0)->digits
  • x/xw (($flags & RUBY_FL_USER2) ? \
  •      ((struct RBignum*)$arg0)->as.ary : \
    
  •      ((struct RBignum*)$arg0)->as.heap.digits)
    
    else
    if ($flags & 0x1f) == 0x0e
    printf "T_FILE: "
    Index: include/ruby/intern.h
    ===================================================================
    — include/ruby/intern.h (e$B%j%S%8%g%se(B 13324)
    +++ include/ruby/intern.h (e$B:n6H%3%T!<e(B)
    @@ -77,6 +77,7 @@
    VALUE rb_big_clone(VALUE);
    void rb_big_2comp(VALUE);
    VALUE rb_big_norm(VALUE);
    +void rb_big_resize(VALUE big, long len);
    VALUE rb_uint2big(VALUE);
    VALUE rb_int2big(SIGNED_VALUE);
    VALUE rb_uint2inum(VALUE);
    Index: include/ruby/ruby.h
    ===================================================================
    — include/ruby/ruby.h (e$B%j%S%8%g%se(B 13324)
    +++ include/ruby/ruby.h (e$B:n6H%3%T!<e(B)
    @@ -547,13 +547,39 @@
    RSTRUCT(st)->as.ary :
    RSTRUCT(st)->as.heap.ptr)

+#define RBIGNUM_EMBED_LEN_MAX ((sizeof(VALUE)*3)/sizeof(BDIGIT))
struct RBignum {
struct RBasic basic;

  • char sign; /* positive:1, negative:0 */
  • long len;
  • void *digits;
  • union {
  •    struct {
    
  •        long len;
    
  •        BDIGIT *digits;
    
  •    } heap;
    
  •    BDIGIT ary[RBIGNUM_EMBED_LEN_MAX];
    
  • } as;
    };
    +#define RBIGNUM_SIGN_BIT FL_USER1
    +/* sign: positive:1, negative:0 */
    +#define RBIGNUM_SIGN(b) ((RBASIC(b)->flags & RBIGNUM_SIGN_BIT) != 0)
    +#define RBIGNUM_SET_SIGN(b,sign) \
  • ((sign) ? (RBASIC(b)->flags |= RBIGNUM_SIGN_BIT) \
  •      : (RBASIC(b)->flags &= ~RBIGNUM_SIGN_BIT))
    

+#define RBIGNUM_POSITIVE_P(b) RBIGNUM_SIGN(b)
+#define RBIGNUM_NEGATIVE_P(b) (!RBIGNUM_SIGN(b))

+#define RBIGNUM_EMBED_FLAG FL_USER2
+#define RBIGNUM_EMBED_LEN_MASK (FL_USER5|FL_USER4|FL_USER3)
+#define RBIGNUM_EMBED_LEN_SHIFT (FL_USHIFT+3)
+#define RBIGNUM_LEN(b) \

  • ((RBASIC(b)->flags & RBIGNUM_EMBED_FLAG) ? \
  • (long)((RBASIC(b)->flags >> RBIGNUM_EMBED_LEN_SHIFT) & \
    
  •        (RBIGNUM_EMBED_LEN_MASK >> RBIGNUM_EMBED_LEN_SHIFT)) : \
    
  • RBIGNUM(b)->as.heap.len)
    

+#define RBIGNUM_DIGITS(b) \

  • ((RBASIC(b)->flags & RBIGNUM_EMBED_FLAG) ? \
  • RBIGNUM(b)->as.ary : \
    
  • RBIGNUM(b)->as.heap.digits)
    

#define R_CAST(st) (struct st*)
#define RBASIC(obj) (R_CAST(RBasic)(obj))
#define ROBJECT(obj) (R_CAST(RObject)(obj))
@@ -631,6 +657,8 @@
#define FL_USER19 RUBY_FL_USER19
RUBY_FL_USER20 = (1<<(FL_USHIFT+20)),
#define FL_USER20 RUBY_FL_USER20

  • RUBY_FL_DUMMY = ~(VALUE)0 >> 1 /* make sizeof(enum
    ruby_value_flags)
  •                                       equal to sizeof(VALUE). */
    

};

#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x))
Index: sprintf.c

— sprintf.c (e$B%j%S%8%g%se(B 13324)
+++ sprintf.c (e$B:n6H%3%T!<e(B)
@@ -658,11 +658,11 @@
}
else {
volatile VALUE tmp1;

  •  if (!RBIGNUM(val)->sign) {
    
  •  if (!RBIGNUM_SIGN(val)) {
         val = rb_big_clone(val);
         rb_big_2comp(val);
     }
    
  •  tmp1 = tmp = rb_big2str0(val, base, RBIGNUM(val)->sign);
    
  •  tmp1 = tmp = rb_big2str0(val, base, RBIGNUM_SIGN(val));
     s = RSTRING_PTR(tmp);
     if (*s == '-') {
         if (base == 10) {
    

@@ -729,7 +729,7 @@
else {
char c;

  •    if (!sign && bignum && !RBIGNUM(val)->sign)
    
  •    if (!sign && bignum && !RBIGNUM_SIGN(val))
     c = sign_bits(base, p);
       else
     c = '0';
    

Index: gc.c

— gc.c (e$B%j%S%8%g%se(B 13324)
+++ gc.c (e$B:n6H%3%T!<e(B)
@@ -1311,8 +1311,8 @@
break;

   case T_BIGNUM:
  • if (RANY(obj)->as.bignum.digits) {
  •  RUBY_CRITICAL(free(RANY(obj)->as.bignum.digits));
    
  • if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) &&
    RBIGNUM_DIGITS(obj)) {
  •  RUBY_CRITICAL(free(RBIGNUM_DIGITS(obj)));
    
    }
    break;
    case T_NODE:
    Index: numeric.c
    ===================================================================
    — numeric.c (e$B%j%S%8%g%se(B 13324)
    +++ numeric.c (e$B:n6H%3%T!<e(B)
    @@ -2684,7 +2684,7 @@
    if (TYPE(idx) == T_BIGNUM) {
    idx = rb_big_norm(idx);
    if (!FIXNUM_P(idx)) {
  •  if (!RBIGNUM(idx)->sign || val >= 0)
    
  •  if (!RBIGNUM_SIGN(idx) || val >= 0)
    
    return INT2FIX(0);
    return INT2FIX(1);
    }
    Index: compar.c
    ===================================================================
    — compar.c (e$B%j%S%8%g%se(B 13324)
    +++ compar.c (e$B:n6H%3%T!<e(B)
    @@ -24,7 +24,7 @@
    }
    if (FIXNUM_P(val)) return FIX2INT(val);
    if (TYPE(val) == T_BIGNUM) {
  • if (RBIGNUM(val)->sign) return 1;
  • if (RBIGNUM_SIGN(val)) return 1;
    return -1;
    }
    if (RTEST(rb_funcall(val, ‘>’, 1, INT2FIX(0)))) return 1;
    Index: bignum.c
    ===================================================================
    — bignum.c (e$B%j%S%8%g%se(B 13324)
    +++ bignum.c (e$B:n6H%3%T!<e(B)
    @@ -25,7 +25,7 @@
    #define USHORT _USHORT
    #endif

-#define BDIGITS(x) ((BDIGIT*)RBIGNUM(x)->digits)
+#define BDIGITS(x) (RBIGNUM_DIGITS(x))
#define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
#define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
#define DIGSPERLONG ((unsigned int)(SIZEOF_LONG/SIZEOF_BDIGITS))
@@ -37,16 +37,66 @@
#define BIGLO(x) ((BDIGIT)((x) & (BIGRAD-1)))
#define BDIGMAX ((BDIGIT)-1)

-#define BIGZEROP(x) (RBIGNUM(x)->len == 0 || (RBIGNUM(x)->len == 1 &&
BDIGITS(x)[0] == 0))
+#define BIGZEROP(x) (RBIGNUM_LEN(x) == 0 || (RBIGNUM_LEN(x) == 1 &&
BDIGITS(x)[0] == 0))

+#define RBIGNUM_SET_LEN(b,l) \

  • ((RBASIC(b)->flags & RBIGNUM_EMBED_FLAG) ? \
  • (RBASIC(b)->flags = (RBASIC(b)->flags & ~RBIGNUM_EMBED_LEN_MASK) | \
  •  ((l) << RBIGNUM_EMBED_LEN_SHIFT)) : \
    
  • (RBIGNUM(b)->as.heap.len = (l)))

+static void
+rb_big_realloc(VALUE big, long len)
+{

  • BDIGIT *ds;
  • if (RBASIC(big)->flags & RBIGNUM_EMBED_FLAG) {
  •    if (RBIGNUM_EMBED_LEN_MAX < len) {
    
  •        ds = ALLOC_N(BDIGIT, len);
    
  •        MEMCPY(ds, RBIGNUM(big)->as.ary, BDIGIT, 
    

RBIGNUM_EMBED_LEN_MAX);

  •        RBIGNUM(big)->as.heap.len = RBIGNUM_LEN(big);
    
  •        RBIGNUM(big)->as.heap.digits = ds;
    
  •        RBASIC(big)->flags &= ~RBIGNUM_EMBED_FLAG;
    
  •    }
    
  • }
  • else {
  •    if (len <= RBIGNUM_EMBED_LEN_MAX) {
    
  •        ds = RBIGNUM(big)->as.heap.digits;
    
  •        RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
    
  •        RBIGNUM_SET_LEN(big, len);
    
  •        MEMCPY(RBIGNUM(big)->as.ary, ds, BDIGIT, len);
    
  •        free(ds);
    
  •    }
    
  •    else {
    
  •        if (RBIGNUM_LEN(big) == 0) {
    
  •            RBIGNUM(big)->as.heap.digits = ALLOC_N(BDIGIT, len);
    
  •        }
    
  •        else {
    
  •            REALLOC_N(RBIGNUM(big)->as.heap.digits, BDIGIT, len);
    
  •        }
    
  •    }
    
  • }
    +}

+void
+rb_big_resize(VALUE big, long len)
+{

  • rb_big_realloc(big, len);
  • RBIGNUM_SET_LEN(big, len);
    +}

static VALUE
bignew_1(VALUE klass, long len, int sign)
{
NEWOBJ(big, struct RBignum);
OBJSETUP(big, klass, T_BIGNUM);

  • big->sign = sign?1:0;
  • big->len = len;
  • big->digits = ALLOC_N(BDIGIT, len);
  • RBIGNUM_SET_SIGN(big, sign?1:0);

  • if (len <= RBIGNUM_EMBED_LEN_MAX) {

  •    RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
    
  •    RBIGNUM_SET_LEN(big, len);
    
  • }

  • else {

  •    rb_big_resize((VALUE)big, len);
    
  • }

    return (VALUE)big;
    }
    @@ -56,9 +106,9 @@
    VALUE
    rb_big_clone(VALUE x)
    {

  • VALUE z = bignew_1(CLASS_OF(x), RBIGNUM(x)->len, RBIGNUM(x)->sign);
  • VALUE z = bignew_1(CLASS_OF(x), RBIGNUM_LEN(x), RBIGNUM_SIGN(x));
  • MEMCPY(BDIGITS(z), BDIGITS(x), BDIGIT, RBIGNUM(x)->len);
  • MEMCPY(BDIGITS(z), BDIGITS(x), BDIGIT, RBIGNUM_LEN(x));
    return z;
    }

@@ -66,7 +116,7 @@
static void
get2comp(VALUE x)
{

  • long i = RBIGNUM(x)->len;
  • long i = RBIGNUM_LEN(x);
    BDIGIT *ds = BDIGITS(x);
    BDIGIT_DBL num;

@@ -77,11 +127,11 @@
num += ds[i];
ds[i++] = BIGLO(num);
num = BIGDN(num);

  • } while (i < RBIGNUM(x)->len);
  • } while (i < RBIGNUM_LEN(x));
    if (num != 0) {
  • REALLOC_N(RBIGNUM(x)->digits, BDIGIT, ++RBIGNUM(x)->len);
  •    rb_big_resize(x, RBIGNUM_LEN(x)+1);
    
    ds = BDIGITS(x);
  • ds[RBIGNUM(x)->len-1] = 1;
  • ds[RBIGNUM_LEN(x)-1] = 1;
    }
    }

@@ -94,19 +144,19 @@
static VALUE
bigtrunc(VALUE x)
{

  • long len = RBIGNUM(x)->len;
  • long len = RBIGNUM_LEN(x);
    BDIGIT *ds = BDIGITS(x);

    if (len == 0) return x;
    while (–len && !ds[len]);

  • RBIGNUM(x)->len = ++len;
  • rb_big_resize(x, len+1);
    return x;
    }

static VALUE
bigfixize(VALUE x)
{

  • long len = RBIGNUM(x)->len;
  • long len = RBIGNUM_LEN(x);
    BDIGIT *ds = BDIGITS(x);

    if (len*SIZEOF_BDIGITS <= sizeof(long)) {
    @@ -115,7 +165,7 @@
    num = BIGUP(num) + ds[len];
    }
    if (num >= 0) {

  •  if (RBIGNUM(x)->sign) {
    
  •  if (RBIGNUM_SIGN(x)) {
    

    if (POSFIXABLE(num)) return LONG2FIX(num);
    }
    else {
    @@ -158,7 +208,7 @@

    i = DIGSPERLONG;
    while (–i && !digits[i]) ;

  • RBIGNUM(big)->len = i+1;
  • RBIGNUM_SET_LEN(big, i+1);
    return big;
    }

@@ -174,7 +224,7 @@
}
big = rb_uint2big(n);
if (neg) {

  • RBIGNUM(big)->sign = 0;
  • RBIGNUM_SET_SIGN(big, 0);
    }
    return big;
    }
    @@ -205,7 +255,7 @@
    q = FIX2LONG(val);
    }
    else {
  • long len = RBIGNUM(val)->len;
  • long len = RBIGNUM_LEN(val);
    BDIGIT *ds;

    if (len > SIZEOF_LONG_LONG/SIZEOF_BDIGITS) {
    @@ -217,7 +267,7 @@
    q = BIGUP(q);
    q += ds[len];
    }

  • if (!RBIGNUM(val)->sign) q = -q;
  • if (!RBIGNUM_SIGN(val)) q = -q;
    }
    memcpy(buf, (char*)&q, SIZEOF_LONG_LONG);
    }
    @@ -253,10 +303,10 @@

    i = DIGSPERLL;
    while (i-- && !digits[i]) ;

  • RBIGNUM(big)->len = i+1;
  • RBIGNUM_SET_LEN(big, i+1);

    if (neg) {

  • RBIGNUM(big)->sign = 0;
  • RBIGNUM_SET_SIGN(big, 0);
    }
    return bignorm(big);
    }
    @@ -275,12 +325,12 @@
    if (FIXNUM_P(val)) {
    val = rb_int2big(FIX2LONG(val));
    }
  • len = RBIGNUM(val)->len * SIZEOF_BDIGITS;
  • len = RBIGNUM_LEN(val) * SIZEOF_BDIGITS;
    if (len > QUAD_SIZE) {
    rb_raise(rb_eRangeError, “bignum too big to convert into `quad
    int’”);
    }
    memcpy(buf, (char*)BDIGITS(val), len);
  • if (!RBIGNUM(val)->sign) {
  • if (!RBIGNUM_SIGN(val)) {
    len = QUAD_SIZE;
    while (len–) {
    *buf = ~*buf;
    @@ -301,7 +351,7 @@
    long len = QUAD_SIZE;
    char tmp = (char)BDIGITS(big);
  • RBIGNUM(big)->sign = 0;
  • RBIGNUM_SET_SIGN(big, 0);
    while (len–) {
    *tmp = ~*tmp;
    tmp++;
    @@ -449,7 +499,7 @@
    }
    else {
    VALUE big = rb_uint2big(val);
  •  RBIGNUM(big)->sign = sign;
    
  •  RBIGNUM_SET_SIGN(big, sign);
     return bignorm(big);
    

    }
    }
    @@ -546,7 +596,7 @@

    i = DIGSPERLL;
    while (i-- && !digits[i]) ;

  • RBIGNUM(big)->len = i+1;
  • RBIGNUM_SET_LEN(big, i+1);
    return big;
    }

@@ -562,7 +612,7 @@
}
big = rb_ull2big(n);
if (neg) {

  • RBIGNUM(big)->sign = 0;
  • RBIGNUM_SET_SIGN(big, 0);
    }
    return big;
    }
    @@ -722,7 +772,7 @@
  • Let a natural number x is given by:
  • x = 2^0 * x_0 + 2^1 * x_1 + … + 2^(Bn_0 - 1) * x_{Bn_0 - 1},
  • where B is BITSPERDIG (i.e. BDIGITS*CHAR_BIT) and n_0 is
    • RBIGNUM(x)->len.
    • RBIGNUM_LEN(x).
    • Now, we assume n_1 = min_n { n | 2^(B*n_0/2) <= b_1^(n_1) }, so
    • it is realized that 2^(Bn_0) <= {b_1}^{2n_1}, where b_1 is a
      @@ -759,7 +809,7 @@
      return 0;
      }
      else {
  •    bits = BITSPERDIG*RBIGNUM(x)->len;
    
  •    bits = BITSPERDIG*RBIGNUM_LEN(x);
    

    }

    return (long)ceil(bits/(2log_2[base - 2]));
    @@ -768,7 +818,7 @@
    static long
    big2str_orig(VALUE x, int base, char
    ptr, long len, long hbase, int
    trim)
    {

  • long i = RBIGNUM(x)->len, j = len;
  • long i = RBIGNUM_LEN(x), j = len;
    BDIGIT* ds = BDIGITS(x);

    while (i && j > 0) {
    @@ -862,15 +912,15 @@
    n1 = big2str_find_n1(x, base);
    ss = rb_str_new(0, 2n1 + 1); / plus one for sign */
    ptr = RSTRING_PTR(ss);

  • ptr[0] = RBIGNUM(x)->sign ? ‘+’ : ‘-’;
  • ptr[0] = RBIGNUM_SIGN(x) ? ‘+’ : ‘-’;

    hbase = base*base;
    #if SIZEOF_BDIGITS > 2
    hbase *= hbase;
    #endif

  • off = !(trim && RBIGNUM(x)->sign); /* erase plus sign if trim */
  • off = !(trim && RBIGNUM_SIGN(x)); /* erase plus sign if trim */
    xx = rb_big_clone(x);
  • RBIGNUM(xx)->sign = 1;
  • RBIGNUM_SET_SIGN(xx, 1);
    if (n1 <= KARATSUBA_DIGITS) {
    len = off + big2str_orig(xx, base, ptr + off, 2*n1, hbase,
    trim);
    }
    @@ -920,7 +970,7 @@
    static VALUE
    big2ulong(VALUE x, const char *type, int check)
    {
  • long len = RBIGNUM(x)->len;
  • long len = RBIGNUM_LEN(x);
    BDIGIT_DBL num;
    BDIGIT *ds;

@@ -942,7 +992,7 @@
rb_big2ulong_pack(VALUE x)
{
VALUE num = big2ulong(x, “unsigned long”, Qfalse);

  • if (!RBIGNUM(x)->sign) {
  • if (!RBIGNUM_SIGN(x)) {
    return -num;
    }
    return num;
    @@ -953,7 +1003,7 @@
    {
    VALUE num = big2ulong(x, “unsigned long”, Qtrue);
  • if (!RBIGNUM(x)->sign) {
  • if (!RBIGNUM_SIGN(x)) {
    if ((SIGNED_VALUE)num < 0) {
    rb_raise(rb_eRangeError, “bignum out of range of unsigned long”);
    }
    @@ -968,10 +1018,10 @@
    VALUE num = big2ulong(x, “long”, Qtrue);

    if ((SIGNED_VALUE)num < 0 &&

  • (RBIGNUM(x)->sign || (SIGNED_VALUE)num != LONG_MIN)) {
  • (RBIGNUM_SIGN(x) || (SIGNED_VALUE)num != LONG_MIN)) {
    rb_raise(rb_eRangeError, “bignum too big to convert into `long’”);
    }
  • if (!RBIGNUM(x)->sign) return -(SIGNED_VALUE)num;
  • if (!RBIGNUM_SIGN(x)) return -(SIGNED_VALUE)num;
    return num;
    }

@@ -980,7 +1030,7 @@
static unsigned LONG_LONG
big2ull(VALUE x, const char *type)
{

  • long len = RBIGNUM(x)->len;
  • long len = RBIGNUM_LEN(x);
    BDIGIT_DBL num;
    BDIGIT *ds;

@@ -1000,7 +1050,7 @@
{
unsigned LONG_LONG num = big2ull(x, “unsigned long long”);

  • if (!RBIGNUM(x)->sign) return -num;
  • if (!RBIGNUM_SIGN(x)) return -num;
    return num;
    }

@@ -1009,11 +1059,11 @@
{
unsigned LONG_LONG num = big2ull(x, “long long”);

  • if ((LONG_LONG)num < 0 && (RBIGNUM(x)->sign
  • if ((LONG_LONG)num < 0 && (RBIGNUM_SIGN(x)
    || (LONG_LONG)num != LLONG_MIN)) {
    rb_raise(rb_eRangeError, “bignum too big to convert into `long
    long’”);
    }
  • if (!RBIGNUM(x)->sign) return -(LONG_LONG)num;
  • if (!RBIGNUM_SIGN(x)) return -(LONG_LONG)num;
    return num;
    }

@@ -1061,13 +1111,13 @@
big2dbl(VALUE x)
{
double d = 0.0;

  • long i = RBIGNUM(x)->len;
  • long i = RBIGNUM_LEN(x);
    BDIGIT *ds = BDIGITS(x);

    while (i–) {
    d = ds[i] + BIGRAD*d;
    }

  • if (!RBIGNUM(x)->sign) d = -d;
  • if (!RBIGNUM_SIGN(x)) d = -d;
    return d;
    }

@@ -1111,7 +1161,7 @@
VALUE
rb_big_cmp(VALUE x, VALUE y)
{

  • long xlen = RBIGNUM(x)->len;
  • long xlen = RBIGNUM_LEN(x);

    switch (TYPE(y)) {
    case T_FIXNUM:
    @@ -1128,18 +1178,18 @@
    return rb_num_coerce_cmp(x, y);
    }

  • if (RBIGNUM(x)->sign > RBIGNUM(y)->sign) return INT2FIX(1);
  • if (RBIGNUM(x)->sign < RBIGNUM(y)->sign) return INT2FIX(-1);
  • if (xlen < RBIGNUM(y)->len)
  • return (RBIGNUM(x)->sign) ? INT2FIX(-1) : INT2FIX(1);
  • if (xlen > RBIGNUM(y)->len)
  • return (RBIGNUM(x)->sign) ? INT2FIX(1) : INT2FIX(-1);
  • if (RBIGNUM_SIGN(x) > RBIGNUM_SIGN(y)) return INT2FIX(1);

  • if (RBIGNUM_SIGN(x) < RBIGNUM_SIGN(y)) return INT2FIX(-1);

  • if (xlen < RBIGNUM_LEN(y))

  • return (RBIGNUM_SIGN(x)) ? INT2FIX(-1) : INT2FIX(1);

  • if (xlen > RBIGNUM_LEN(y))

  • return (RBIGNUM_SIGN(x)) ? INT2FIX(1) : INT2FIX(-1);

    while(xlen-- && (BDIGITS(x)[xlen]==BDIGITS(y)[xlen]));
    if (-1 == xlen) return INT2FIX(0);
    return (BDIGITS(x)[xlen] > BDIGITS(y)[xlen]) ?

  • (RBIGNUM(x)->sign ? INT2FIX(1) : INT2FIX(-1)) :
  •  (RBIGNUM(x)->sign ? INT2FIX(-1) : INT2FIX(1));
    
  • (RBIGNUM_SIGN(x) ? INT2FIX(1) : INT2FIX(-1)) :
  •  (RBIGNUM_SIGN(x) ? INT2FIX(-1) : INT2FIX(1));
    

}

/*
@@ -1174,9 +1224,9 @@
default:
return rb_equal(y, x);
}

  • if (RBIGNUM(x)->sign != RBIGNUM(y)->sign) return Qfalse;
  • if (RBIGNUM(x)->len != RBIGNUM(y)->len) return Qfalse;
  • if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM(y)->len) != 0)
    return Qfalse;
  • if (RBIGNUM_SIGN(x) != RBIGNUM_SIGN(y)) return Qfalse;
  • if (RBIGNUM_LEN(x) != RBIGNUM_LEN(y)) return Qfalse;
  • if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM_LEN(y)) != 0)
    return Qfalse;
    return Qtrue;
    }

@@ -1195,9 +1245,9 @@
rb_big_eql(VALUE x, VALUE y)
{
if (TYPE(y) != T_BIGNUM) return Qfalse;

  • if (RBIGNUM(x)->sign != RBIGNUM(y)->sign) return Qfalse;
  • if (RBIGNUM(x)->len != RBIGNUM(y)->len) return Qfalse;
  • if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM(y)->len) != 0)
    return Qfalse;
  • if (RBIGNUM_SIGN(x) != RBIGNUM_SIGN(y)) return Qfalse;
  • if (RBIGNUM_LEN(x) != RBIGNUM_LEN(y)) return Qfalse;
  • if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM_LEN(y)) != 0)
    return Qfalse;
    return Qtrue;
    }

@@ -1213,7 +1263,7 @@
{
VALUE z = rb_big_clone(x);

  • RBIGNUM(z)->sign = !RBIGNUM(x)->sign;
  • RBIGNUM_SET_SIGN(z, !RBIGNUM_SIGN(x));

    return bignorm(z);
    }
    @@ -1237,15 +1287,15 @@
    BDIGIT *ds;
    long i;

  • if (!RBIGNUM(x)->sign) get2comp(z);
  • if (!RBIGNUM_SIGN(x)) get2comp(z);
    ds = BDIGITS(z);
  • i = RBIGNUM(x)->len;
  • i = RBIGNUM_LEN(x);
    if (!i) return INT2FIX(~(SIGNED_VALUE)0);
    while (i–) {
    ds[i] = ~ds[i];
    }
  • RBIGNUM(z)->sign = !RBIGNUM(z)->sign;
  • if (RBIGNUM(x)->sign) get2comp(z);
  • RBIGNUM_SET_SIGN(z, !RBIGNUM_SIGN(z));

  • if (RBIGNUM_SIGN(x)) get2comp(z);

    return bignorm(z);
    }
    @@ -1256,13 +1306,13 @@
    VALUE z = 0;
    BDIGIT *zds;
    BDIGIT_DBL_SIGNED num;

  • long i = RBIGNUM(x)->len;
  • long i = RBIGNUM_LEN(x);

    /* if x is larger than y, swap */

  • if (RBIGNUM(x)->len < RBIGNUM(y)->len) {
  • if (RBIGNUM_LEN(x) < RBIGNUM_LEN(y)) {
    z = x; x = y; y = z; /* swap x y */
    }
  • else if (RBIGNUM(x)->len == RBIGNUM(y)->len) {
  • else if (RBIGNUM_LEN(x) == RBIGNUM_LEN(y)) {
    while (i > 0) {
    i–;
    if (BDIGITS(x)[i] > BDIGITS(y)[i]) {
    @@ -1275,20 +1325,20 @@
    }
    }
  • z = bignew(RBIGNUM(x)->len, z==0);
  • z = bignew(RBIGNUM_LEN(x), z==0);
    zds = BDIGITS(z);
  • for (i = 0, num = 0; i < RBIGNUM(y)->len; i++) {
  • for (i = 0, num = 0; i < RBIGNUM_LEN(y); i++) {
    num += (BDIGIT_DBL_SIGNED)BDIGITS(x)[i] - BDIGITS(y)[i];
    zds[i] = BIGLO(num);
    num = BIGDN(num);
    }
  • while (num && i < RBIGNUM(x)->len) {
  • while (num && i < RBIGNUM_LEN(x)) {
    num += BDIGITS(x)[i];
    zds[i++] = BIGLO(num);
    num = BIGDN(num);
    }
  • while (i < RBIGNUM(x)->len) {
  • while (i < RBIGNUM_LEN(x)) {
    zds[i] = BDIGITS(x)[i];
    i++;
    }
    @@ -1303,28 +1353,28 @@
    BDIGIT_DBL num;
    long i, len;
  • sign = (sign == RBIGNUM(y)->sign);
  • if (RBIGNUM(x)->sign != sign) {
  • sign = (sign == RBIGNUM_SIGN(y));
  • if (RBIGNUM_SIGN(x) != sign) {
    if (sign) return bigsub(y, x);
    return bigsub(x, y);
    }
  • if (RBIGNUM(x)->len > RBIGNUM(y)->len) {
  • len = RBIGNUM(x)->len + 1;
  • if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
  • len = RBIGNUM_LEN(x) + 1;
    z = x; x = y; y = z;
    }
    else {
  • len = RBIGNUM(y)->len + 1;
  • len = RBIGNUM_LEN(y) + 1;
    }
    z = bignew(len, sign);
  • len = RBIGNUM(x)->len;
  • len = RBIGNUM_LEN(x);
    for (i = 0, num = 0; i < len; i++) {
    num += (BDIGIT_DBL)BDIGITS(x)[i] + BDIGITS(y)[i];
    BDIGITS(z)[i] = BIGLO(num);
    num = BIGDN(num);
    }
  • len = RBIGNUM(y)->len;
  • len = RBIGNUM_LEN(y);
    while (num && i < len) {
    num += BDIGITS(y)[i];
    BDIGITS(z)[i++] = BIGLO(num);
    @@ -1412,15 +1462,15 @@
    return rb_num_coerce_bin(x, y);
    }
  • j = RBIGNUM(x)->len + RBIGNUM(y)->len + 1;
  • z = bignew(j, RBIGNUM(x)->sign==RBIGNUM(y)->sign);
  • j = RBIGNUM_LEN(x) + RBIGNUM_LEN(y) + 1;
  • z = bignew(j, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
    zds = BDIGITS(z);
    while (j–) zds[j] = 0;
  • for (i = 0; i < RBIGNUM(x)->len; i++) {
  • for (i = 0; i < RBIGNUM_LEN(x); i++) {
    BDIGIT_DBL dd = BDIGITS(x)[i];
    if (dd == 0) continue;
    n = 0;
  • for (j = 0; j < RBIGNUM(y)->len; j++) {
  • for (j = 0; j < RBIGNUM_LEN(y); j++) {
    BDIGIT_DBL ee = n + (BDIGIT_DBL)dd * BDIGITS(y)[j];
    n = zds[i + j] + ee;
    if (ee) zds[i + j] = BIGLO(n);
    @@ -1449,7 +1499,7 @@
    static void
    bigdivrem(VALUE x, VALUE y, VALUE *divp, VALUE *modp)
    {
  • long nx = RBIGNUM(x)->len, ny = RBIGNUM(y)->len;
  • long nx = RBIGNUM_LEN(x), ny = RBIGNUM_LEN(y);
    long i, j;
    VALUE yy, z;
    BDIGIT *xds, *yds, *zds, *tds;
    @@ -1475,15 +1525,15 @@
    zds[i] = (BDIGIT)(t2 / dd);
    t2 %= dd;
    }
  • RBIGNUM(z)->sign = RBIGNUM(x)->sign==RBIGNUM(y)->sign;
  • RBIGNUM_SET_SIGN(z, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
    if (modp) {
    *modp = rb_uint2big((VALUE)t2);
  •  RBIGNUM(*modp)->sign = RBIGNUM(x)->sign;
    
  •  RBIGNUM_SET_SIGN(*modp, RBIGNUM_SIGN(x));
    
    }
    if (divp) *divp = z;
    return;
    }
  • z = bignew(nx==ny?nx+2:nx+1, RBIGNUM(x)->sign==RBIGNUM(y)->sign);
  • z = bignew(nx==ny?nx+2:nx+1, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
    zds = BDIGITS(z);
    if (nx==ny) zds[nx+1] = 0;
    while (!yds[ny-1]) ny–;
    @@ -1554,7 +1604,7 @@
    zds = BDIGITS(*divp);
    j = (nx==ny ? nx+2 : nx+1) - ny;
    for (i = 0;i < j;i++) zds[i] = zds[i+ny];
  • RBIGNUM(*divp)->len = i;
  • RBIGNUM_SET_LEN(divp, i);
    }
    if (modp) { /
    normalize remainder */
    *modp = rb_big_clone(z);
    @@ -1569,8 +1619,8 @@
    t2 = BIGUP(q);
    }
    }
  • RBIGNUM(*modp)->len = ny;
  • RBIGNUM(*modp)->sign = RBIGNUM(x)->sign;
  • RBIGNUM_SET_LEN(*modp, ny);
  • RBIGNUM_SET_SIGN(*modp, RBIGNUM_SIGN(x));
    }
    }

@@ -1580,7 +1630,7 @@
VALUE mod;

 bigdivrem(x, y, divp, &mod);
  • if (RBIGNUM(x)->sign != RBIGNUM(y)->sign && !BIGZEROP(mod)) {
  • if (RBIGNUM_SIGN(x) != RBIGNUM_SIGN(y) && !BIGZEROP(mod)) {
    if (divp) *divp = bigadd(*divp, rb_int2big(1), 0);
    if (modp) *modp = bigadd(mod, y, 1);
    }
    @@ -1767,8 +1817,8 @@
    VALUE z;
    int ex, ey;
  • ex = (RBIGNUM(bigtrunc(x))->len - 1) * BITSPERDIG;
  • ex += bdigbitsize(BDIGITS(x)[RBIGNUM(x)->len - 1]);
  • ex = (RBIGNUM_LEN(bigtrunc(x)) - 1) * BITSPERDIG;
  • ex += bdigbitsize(BDIGITS(x)[RBIGNUM_LEN(x) - 1]);
    ex -= 2 * DBL_BIGDIG * BITSPERDIG;
    if (ex) x = big_shift(x, ex);

@@ -1776,8 +1826,8 @@
case T_FIXNUM:
y = rb_int2big(FIX2LONG(y));
case T_BIGNUM: {

  •  ey = (RBIGNUM(bigtrunc(y))->len - 1) * BITSPERDIG;
    
  •  ey += bdigbitsize(BDIGITS(y)[RBIGNUM(y)->len - 1]);
    
  •  ey = (RBIGNUM_LEN(bigtrunc(y)) - 1) * BITSPERDIG;
    
  •  ey += bdigbitsize(BDIGITS(y)[RBIGNUM_LEN(y) - 1]);
     ey -= DBL_BIGDIG * BITSPERDIG;
     if (ey) y = big_shift(y, ey);
    
    bignum:
    @@ -1812,7 +1862,7 @@
    static VALUE
    bigsqr(VALUE x)
    {
  • long len = RBIGNUM(x)->len, k = len / 2, i;
  • long len = RBIGNUM_LEN(x), k = len / 2, i;
    VALUE a, b, a2, z;
    BDIGIT_DBL num;

@@ -1827,26 +1877,30 @@

 a2 = bigtrunc(bigsqr(a));
 z = bigsqr(b);
  • REALLOC_N(RBIGNUM(z)->digits, BDIGIT, (len = 2 * k +
    RBIGNUM(a2)->len) + 1);
  • while (RBIGNUM(z)->len < 2 * k) BDIGITS(z)[RBIGNUM(z)->len++] = 0;
  • MEMCPY(BDIGITS(z) + 2 * k, BDIGITS(a2), BDIGIT, RBIGNUM(a2)->len);
  • RBIGNUM(z)->len = len;
  • rb_big_realloc(z, (len = 2 * k + RBIGNUM_LEN(a2)) + 1);
  • while (RBIGNUM_LEN(z) < 2 * k) {
  •      BDIGITS(z)[RBIGNUM_LEN(z)] = 0;
    
  •      RBIGNUM_SET_LEN(z, RBIGNUM_LEN(z)+1);
    
  • }
  • MEMCPY(BDIGITS(z) + 2 * k, BDIGITS(a2), BDIGIT, RBIGNUM_LEN(a2));
  • RBIGNUM_SET_LEN(z, len);
    a2 = bigtrunc(rb_big_mul0(a, b));
  • len = RBIGNUM(a2)->len;
  • len = RBIGNUM_LEN(a2);
    for (i = 0, num = 0; i < len; i++) {
    num += (BDIGIT_DBL)BDIGITS(z)[i + k] + ((BDIGIT_DBL)BDIGITS(a2)[i] <<
    1);
    BDIGITS(z)[i + k] = BIGLO(num);
    num = BIGDN(num);
    }
    if (num) {
  • len = RBIGNUM(z)->len;
  • len = RBIGNUM_LEN(z);
    for (i += k; i < len && num; ++i) {
    num += (BDIGIT_DBL)BDIGITS(z)[i];
    BDIGITS(z)[i] = BIGLO(num);
    num = BIGDN(num);
    }
    if (num) {
  •  BDIGITS(z)[RBIGNUM(z)->len++] = BIGLO(num);
    
  •  BDIGITS(z)[RBIGNUM_LEN(z)] = BIGLO(num);
    
  •        RBIGNUM_SET_LEN(z, RBIGNUM_LEN(z)+1);
    
    }
    }
    return bigtrunc(z);
    @@ -1889,8 +1943,8 @@
    SIGNED_VALUE mask;
    const long BIGLEN_LIMIT = 1024*1024 / SIZEOF_BDIGITS;
  •  if ((RBIGNUM(x)->len > BIGLEN_LIMIT) ||
    
  • (RBIGNUM(x)->len > BIGLEN_LIMIT / yy)) {
  •  if ((RBIGNUM_LEN(x) > BIGLEN_LIMIT) ||
    
  • (RBIGNUM_LEN(x) > BIGLEN_LIMIT / yy)) {
    rb_warn(“in a**b, b may be too big”);
    d = (double)yy;
    break;
    @@ -1932,29 +1986,29 @@
    if (FIXNUM_P(y)) {
    y = rb_int2big(FIX2LONG(y));
    }
  • if (!RBIGNUM(y)->sign) {
  • if (!RBIGNUM_SIGN(y)) {
    y = rb_big_clone(y);
    get2comp(y);
    }
  • if (!RBIGNUM(x)->sign) {
  • if (!RBIGNUM_SIGN(x)) {
    x = rb_big_clone(x);
    get2comp(x);
    }
  • if (RBIGNUM(x)->len > RBIGNUM(y)->len) {
  • l1 = RBIGNUM(y)->len;
  • l2 = RBIGNUM(x)->len;
  • if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
  • l1 = RBIGNUM_LEN(y);
  • l2 = RBIGNUM_LEN(x);
    ds1 = BDIGITS(y);
    ds2 = BDIGITS(x);
  • sign = RBIGNUM(y)->sign;
  • sign = RBIGNUM_SIGN(y);
    }
    else {
  • l1 = RBIGNUM(x)->len;
  • l2 = RBIGNUM(y)->len;
  • l1 = RBIGNUM_LEN(x);
  • l2 = RBIGNUM_LEN(y);
    ds1 = BDIGITS(x);
    ds2 = BDIGITS(y);
  • sign = RBIGNUM(x)->sign;
  • sign = RBIGNUM_SIGN(x);
    }
  • z = bignew(l2, RBIGNUM(x)->sign || RBIGNUM(y)->sign);
  • z = bignew(l2, RBIGNUM_SIGN(x) || RBIGNUM_SIGN(y));
    zds = BDIGITS(z);

    for (i=0; i<l1; i++) {
    @@ -1963,7 +2017,7 @@
    for (; i<l2; i++) {
    zds[i] = sign?0:ds2[i];
    }

  • if (!RBIGNUM(z)->sign) get2comp(z);
  • if (!RBIGNUM_SIGN(z)) get2comp(z);
    return bignorm(z);
    }

@@ -1988,29 +2042,29 @@
y = rb_int2big(FIX2LONG(y));
}

  • if (!RBIGNUM(y)->sign) {
  • if (!RBIGNUM_SIGN(y)) {
    y = rb_big_clone(y);
    get2comp(y);
    }
  • if (!RBIGNUM(x)->sign) {
  • if (!RBIGNUM_SIGN(x)) {
    x = rb_big_clone(x);
    get2comp(x);
    }
  • if (RBIGNUM(x)->len > RBIGNUM(y)->len) {
  • l1 = RBIGNUM(y)->len;
  • l2 = RBIGNUM(x)->len;
  • if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
  • l1 = RBIGNUM_LEN(y);
  • l2 = RBIGNUM_LEN(x);
    ds1 = BDIGITS(y);
    ds2 = BDIGITS(x);
  • sign = RBIGNUM(y)->sign;
  • sign = RBIGNUM_SIGN(y);
    }
    else {
  • l1 = RBIGNUM(x)->len;
  • l2 = RBIGNUM(y)->len;
  • l1 = RBIGNUM_LEN(x);
  • l2 = RBIGNUM_LEN(y);
    ds1 = BDIGITS(x);
    ds2 = BDIGITS(y);
  • sign = RBIGNUM(x)->sign;
  • sign = RBIGNUM_SIGN(x);
    }
  • z = bignew(l2, RBIGNUM(x)->sign && RBIGNUM(y)->sign);
  • z = bignew(l2, RBIGNUM_SIGN(x) && RBIGNUM_SIGN(y));
    zds = BDIGITS(z);

    for (i=0; i<l1; i++) {
    @@ -2019,7 +2073,7 @@
    for (; i<l2; i++) {
    zds[i] = sign?ds2[i]:(BIGRAD-1);
    }

  • if (!RBIGNUM(z)->sign) get2comp(z);
  • if (!RBIGNUM_SIGN(z)) get2comp(z);

    return bignorm(z);
    }
    @@ -2046,31 +2100,31 @@
    y = rb_int2big(FIX2LONG(y));
    }

  • if (!RBIGNUM(y)->sign) {
  • if (!RBIGNUM_SIGN(y)) {
    y = rb_big_clone(y);
    get2comp(y);
    }
  • if (!RBIGNUM(x)->sign) {
  • if (!RBIGNUM_SIGN(x)) {
    x = rb_big_clone(x);
    get2comp(x);
    }
  • if (RBIGNUM(x)->len > RBIGNUM(y)->len) {
  • l1 = RBIGNUM(y)->len;
  • l2 = RBIGNUM(x)->len;
  • if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
  • l1 = RBIGNUM_LEN(y);
  • l2 = RBIGNUM_LEN(x);
    ds1 = BDIGITS(y);
    ds2 = BDIGITS(x);
  • sign = RBIGNUM(y)->sign;
  • sign = RBIGNUM_SIGN(y);
    }
    else {
  • l1 = RBIGNUM(x)->len;
  • l2 = RBIGNUM(y)->len;
  • l1 = RBIGNUM_LEN(x);
  • l2 = RBIGNUM_LEN(y);
    ds1 = BDIGITS(x);
    ds2 = BDIGITS(y);
  • sign = RBIGNUM(x)->sign;
  • sign = RBIGNUM_SIGN(x);
    }
  • RBIGNUM(x)->sign = RBIGNUM(x)->sign?1:0;
  • RBIGNUM(y)->sign = RBIGNUM(y)->sign?1:0;
  • z = bignew(l2, !(RBIGNUM(x)->sign ^ RBIGNUM(y)->sign));
  • RBIGNUM_SET_SIGN(x, RBIGNUM_SIGN(x)?1:0);

  • RBIGNUM_SET_SIGN(y, RBIGNUM_SIGN(y)?1:0);

  • z = bignew(l2, !(RBIGNUM_SIGN(x) ^ RBIGNUM_SIGN(y)));
    zds = BDIGITS(z);

    for (i=0; i<l1; i++) {
    @@ -2079,7 +2133,7 @@
    for (; i<l2; i++) {
    zds[i] = sign?ds2[i]:~ds2[i];
    }

  • if (!RBIGNUM(z)->sign) get2comp(z);
  • if (!RBIGNUM_SIGN(z)) get2comp(z);

    return bignorm(z);
    }
    @@ -2087,9 +2141,9 @@
    static VALUE
    check_shiftdown(VALUE y, VALUE x)
    {

  • if (!RBIGNUM(x)->len) return INT2FIX(0);
  • if (RBIGNUM(y)->len > SIZEOF_LONG / SIZEOF_BDIGITS) {
  • return RBIGNUM(x)->sign ? INT2FIX(0) : INT2FIX(-1);
  • if (!RBIGNUM_LEN(x)) return INT2FIX(0);
  • if (RBIGNUM_LEN(y) > SIZEOF_LONG / SIZEOF_BDIGITS) {
  • return RBIGNUM_SIGN(x) ? INT2FIX(0) : INT2FIX(-1);
    }
    return Qnil;
    }
    @@ -2117,7 +2171,7 @@
    break;
    }
    else if (TYPE(y) == T_BIGNUM) {
  •  if (!RBIGNUM(y)->sign) {
    
  •  if (!RBIGNUM_SIGN(y)) {
    
    VALUE t = check_shiftdown(y, x);
    if (!NIL_P(t)) return t;
    neg = 1;
    @@ -2142,8 +2196,8 @@
    BDIGIT_DBL num = 0;
    long len, i;
  • len = RBIGNUM(x)->len;
  • z = bignew(len+s1+1, RBIGNUM(x)->sign);
  • len = RBIGNUM_LEN(x);
  • z = bignew(len+s1+1, RBIGNUM_SIGN(x));
    zds = BDIGITS(z);
    for (i=0; i<s1; i++) {
    *zds++ = 0;
    @@ -2181,7 +2235,7 @@
    break;
    }
    else if (TYPE(y) == T_BIGNUM) {
  •  if (RBIGNUM(y)->sign) {
    
  •  if (RBIGNUM_SIGN(y)) {
    
    VALUE t = check_shiftdown(y, x);
    if (!NIL_P(t)) return t;
    }
    @@ -2209,24 +2263,24 @@
    long i, j;
    volatile VALUE save_x;
  • if (s1 > RBIGNUM(x)->len) {
  • if (RBIGNUM(x)->sign)
  • if (s1 > RBIGNUM_LEN(x)) {
  • if (RBIGNUM_SIGN(x))
    return INT2FIX(0);
    else
    return INT2FIX(-1);
    }
  • if (!RBIGNUM(x)->sign) {
  • if (!RBIGNUM_SIGN(x)) {
    save_x = x = rb_big_clone(x);
    get2comp(x);
    }
    xds = BDIGITS(x);
  • i = RBIGNUM(x)->len; j = i - s1;
  • i = RBIGNUM_LEN(x); j = i - s1;
    if (j == 0) {
  • if (RBIGNUM(x)->sign) return INT2FIX(0);
  • if (RBIGNUM_SIGN(x)) return INT2FIX(0);
    else return INT2FIX(-1);
    }
  • z = bignew(j, RBIGNUM(x)->sign);
  • if (!RBIGNUM(x)->sign) {
  • z = bignew(j, RBIGNUM_SIGN(x));
  • if (!RBIGNUM_SIGN(x)) {
    num = ((BDIGIT_DBL)~0) << BITSPERDIG;
    }
    zds = BDIGITS(z);
    @@ -2235,7 +2289,7 @@
    zds[j] = BIGLO(num);
    num = BIGUP(xds[i]);
    }
  • if (!RBIGNUM(x)->sign) {
  • if (!RBIGNUM_SIGN(x)) {
    get2comp(z);
    }
    return bignorm(z);
    @@ -2269,11 +2323,11 @@
    long i, s1, s2;

    if (TYPE(y) == T_BIGNUM) {

  • if (!RBIGNUM(y)->sign)
  • if (!RBIGNUM_SIGN(y))
    return INT2FIX(0);
  • if (RBIGNUM(bigtrunc(y))->len > SIZEOF_VALUE/SIZEOF_BDIGITS) {
  • if (RBIGNUM_LEN(bigtrunc(y)) > SIZEOF_VALUE/SIZEOF_BDIGITS) {
    out_of_range:
  •  return RBIGNUM(x)->sign ? INT2FIX(0) : INT2FIX(1);
    
  •  return RBIGNUM_SIGN(x) ? INT2FIX(0) : INT2FIX(1);
    
    }
    shift = big2ulong(y, “long”, Qfalse);
    }
    @@ -2285,8 +2339,8 @@
    s1 = shift/BITSPERDIG;
    s2 = shift%BITSPERDIG;
  • if (s1 >= RBIGNUM(x)->len) goto out_of_range;
  • if (!RBIGNUM(x)->sign) {
  • if (s1 >= RBIGNUM_LEN(x)) goto out_of_range;
  • if (!RBIGNUM_SIGN(x)) {
    xds = BDIGITS(x);
    i = 0; num = 1;
    while (num += ~xds[i], ++i <= s1) {
    @@ -2313,7 +2367,7 @@
    {
    int hash;
  • hash = rb_memhash(BDIGITS(x), sizeof(BDIGIT)*RBIGNUM(x)->len) ^
    RBIGNUM(x)->sign;
  • hash = rb_memhash(BDIGITS(x), sizeof(BDIGIT)*RBIGNUM_LEN(x)) ^
    RBIGNUM_SIGN(x);
    return INT2FIX(hash);
    }

@@ -2350,9 +2404,9 @@
static VALUE
rb_big_abs(VALUE x)
{

  • if (!RBIGNUM(x)->sign) {
  • if (!RBIGNUM_SIGN(x)) {
    x = rb_big_clone(x);
  • RBIGNUM(x)->sign = 1;
  • RBIGNUM_SET_SIGN(x, 1);
    }
    return x;
    }
    @@ -2372,7 +2426,7 @@
    static VALUE
    rb_big_size(VALUE big)
    {
  • return LONG2FIX(RBIGNUM(big)->len*SIZEOF_BDIGITS);
  • return LONG2FIX(RBIGNUM_LEN(big)*SIZEOF_BDIGITS);
    }

/*
Index: marshal.c

— marshal.c (e$B%j%S%8%g%se(B 13324)
+++ marshal.c (e$B:n6H%3%T!<e(B)
@@ -514,9 +514,9 @@
case T_BIGNUM:
w_byte(TYPE_BIGNUM, arg);
{

  • char sign = RBIGNUM(obj)->sign ? ‘+’ : ‘-’;
  • long len = RBIGNUM(obj)->len;
  • BDIGIT *d = RBIGNUM(obj)->digits;
  • char sign = RBIGNUM_SIGN(obj) ? ‘+’ : ‘-’;

  • long len = RBIGNUM_LEN(obj);

  • BDIGIT *d = RBIGNUM_DIGITS(obj);

    w_byte(sign, arg);
    w_long(SHORTLEN(len), arg); /* w_short? */
    @@ -1060,21 +1060,21 @@

    NEWOBJ(big, struct RBignum);
    OBJSETUP(big, rb_cBignum, T_BIGNUM);

  •  big->sign = (r_byte(arg) == '+');
    
  •  RBIGNUM_SET_SIGN(big, (r_byte(arg) == '+'));
     len = r_long(arg);
     data = r_bytes0(len * 2, arg);
    

#if SIZEOF_BDIGITS == SIZEOF_SHORT

  •  big->len = len;
    
  •        rb_big_resize((VALUE)big, len);
    

#else

  •  big->len = (len + 1) * 2 / sizeof(BDIGIT);
    
  •        rb_big_resize((VALUE)big, (len + 1) * 2 / sizeof(BDIGIT));
    

#endif

  •  big->digits = digits = ALLOC_N(BDIGIT, big->len);
    
  •        digits = RBIGNUM_DIGITS(big);
     MEMCPY(digits, RSTRING_PTR(data), char, len * 2);
    

#if SIZEOF_BDIGITS > SIZEOF_SHORT
MEMZERO((char *)digits + len * 2, char,

  •    big->len * sizeof(BDIGIT) - len * 2);
    
  •    RBIGNUM_LEN(big) * sizeof(BDIGIT) - len * 2);
    

#endif

  •  len = big->len;
    
  •  len = RBIGNUM_LEN(big);
     while (len > 0) {
    
    unsigned char *p = (unsigned char *)digits;
    BDIGIT num = 0;
    Index: test/ruby/test_integer.rb
    ===================================================================
    — test/ruby/test_integer.rb (e$B%j%S%8%g%se(B 13324)
    +++ test/ruby/test_integer.rb (e$B:n6H%3%T!<e(B)
    @@ -2,6 +2,12 @@

class TestInteger < Test::Unit::TestCase
VS = [

  • -0x1000000000000000000000000000000000000000000000002,
  • -0x1000000000000000000000000000000000000000000000001,
  • -0x1000000000000000000000000000000000000000000000000,
  • -0x1000000000000000000000002,
  • -0x1000000000000000000000001,
  • -0x1000000000000000000000000,
    -0x10000000000000002,
    -0x10000000000000001,
    -0x10000000000000000,
    @@ -89,6 +95,12 @@
    0xffffffffffffffff,
    0x10000000000000000,
    0x10000000000000001,
  • 0xffffffffffffffffffffffff,
  • 0x1000000000000000000000000,
  • 0x1000000000000000000000001,
  • 0xffffffffffffffffffffffffffffffffffffffffffffffff,
  • 0x1000000000000000000000000000000000000000000000000,
  • 0x1000000000000000000000000000000000000000000000001
    ]

#VS.map! {|v| 0x4000000000000000.coerce(v)[0] }
Index: random.c

— random.c (e$B%j%S%8%g%se(B 13324)
+++ random.c (e$B:n6H%3%T!<e(B)
@@ -204,7 +204,7 @@
len = sizeof(VALUE);
break;
case T_BIGNUM:

  •      len = RBIGNUM(seed)->len * SIZEOF_BDIGITS;
    
  •      len = RBIGNUM_LEN(seed) * SIZEOF_BDIGITS;
         if (len == 0)
             len = 4;
         break;
    

@@ -223,12 +223,12 @@
}
else {
int i, j;

  •    for (i = RBIGNUM(seed)->len-1; 0 <= i; i--) {
    
  •    for (i = RBIGNUM_LEN(seed)-1; 0 <= i; i--) {
           j = i * SIZEOF_BDIGITS / 4;
    

#if SIZEOF_BDIGITS < 4
buf[j] <<= SIZEOF_BDIGITS * 8;
#endif

  •        buf[j] |= ((BDIGIT *)RBIGNUM(seed)->digits)[i];
    
  •        buf[j] |= RBIGNUM_DIGITS(seed)[i];
       }
    

    }
    while (1 < len && buf[len-1] == 0) {
    @@ -263,12 +263,12 @@
    OBJSETUP(big, rb_cBignum, T_BIGNUM);

    seed_len = 4 * sizeof(long);

  • big->sign = 1;
  • big->len = seed_len / SIZEOF_BDIGITS + 1;
  • digits = big->digits = ALLOC_N(BDIGIT, big->len);
  • seed = (unsigned long *)big->digits;
  • RBIGNUM_SET_SIGN(big, 1);
  • rb_big_resize((VALUE)big, seed_len / SIZEOF_BDIGITS + 1);
  • digits = RBIGNUM_DIGITS(big);
  • seed = (unsigned long *)RBIGNUM_DIGITS(big);
  • memset(digits, 0, big->len * SIZEOF_BDIGITS);
  • memset(digits, 0, RBIGNUM_LEN(big) * SIZEOF_BDIGITS);

#ifdef S_ISCHR
if ((fd = open("/dev/urandom", O_RDONLY
@@ -296,7 +296,7 @@
seed[3] ^= (unsigned long)&seed;

 /* set leading-zero-guard if need. */
  • digits[big->len-1] = digits[big->len-2] <= 1 ? 1 : 0;
  • digits[RBIGNUM_LEN(big)-1] = digits[RBIGNUM_LEN(big)-2] <= 1 ? 1 :
    0;

    return rb_big_norm((VALUE)big);
    }
    @@ -370,20 +370,20 @@
    struct RBignum *val;
    int i, len, boundary;

  • len = (limit->len * SIZEOF_BDIGITS + 3) / 4;
  • len = (RBIGNUM_LEN(limit) * SIZEOF_BDIGITS + 3) / 4;
    val = (struct RBignum *)rb_big_clone((VALUE)limit);
  • val->sign = 1;
  • RBIGNUM_SET_SIGN(val, 1);
    #if SIZEOF_BDIGITS == 2
    -# define BIG_GET32(big,i) (((BDIGIT *)(big)->digits)[(i)*2] | \
  •                       ((i)*2+1 < (big)->len ? (((BDIGIT 
    

*)(big)->digits)[(i)*2+1] << 16)
+# define BIG_GET32(big,i) (RBIGNUM_DIGITS(big)[(i)*2] | \

  •                       ((i)*2+1 < RBIGNUM_DIGITS(big) ? 
    

(RBIGNUM_DIGITS(big)[(i)*2+1] << 16)
: 0))
-# define BIG_SET32(big,i,d) ((((BDIGIT *)(big)->digits)[(i)*2] = (d) &
0xffff), \

  •                         ((i)*2+1 < (big)->len ? (((BDIGIT 
    

*)(big)->digits)[(i)*2+1] = (d) >> 16)
+# define BIG_SET32(big,i,d) ((RBIGNUM_DIGITS(big)[(i)*2] = (d) &
0xffff), \

  •                         ((i)*2+1 < RBIGNUM_DIGITS(big) ? 
    

(RBIGNUM_DIGITS(big)[(i)2+1] = (d) >> 16)
: 0))
#else
/
SIZEOF_BDIGITS == 4 */
-# define BIG_GET32(big,i) (((BDIGIT *)(big)->digits)[i])
-# define BIG_SET32(big,i,d) (((BDIGIT *)(big)->digits)[i] = (d))
+# define BIG_GET32(big,i) (RBIGNUM_DIGITS(big)[i])
+# define BIG_SET32(big,i,d) (RBIGNUM_DIGITS(big)[i] = (d))
#endif
retry:
mask = 0;
@@ -450,9 +450,9 @@
bignum:
{
struct RBignum *limit = (struct RBignum *)vmax;

  •        if (!limit->sign) {
    
  •        if (!RBIGNUM_SIGN(limit)) {
               limit = (struct RBignum *)rb_big_clone(vmax);
    
  •            limit->sign = 1;
    
  •            RBIGNUM_SET_SIGN(limit, 1);
           }
           limit = (struct RBignum *)rb_big_minus((VALUE)limit, 
    

INT2FIX(1));
if (FIXNUM_P((VALUE)limit)) {