From 2c8e7a50c1db8fea3fb012052828ad1eea51883f Mon Sep 17 00:00:00 2001 From: akr Date: Sat, 1 Sep 2007 12:02:36 +0000 Subject: * include/ruby/ruby.h (struct RBignum): embed digits in RBignum for small bignums. * bignum.c: RBignum embeded digits implemented. * include/ruby/intern.h: declare rb_big_resize. * gc.c: don't free embedded digits. * numeric.c: replace direct bignum field accessor by abstract field accessor such as RBIGNUM(val)->sign to RBIGNUM_SIGN(val). * sprintf.c: ditto. * compar.c: ditto. * marshal.c: ditto. * random.c: ditto. * .gdbinit: support embedded small bignums. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13330 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- .gdbinit | 12 +- ChangeLog | 24 +++ bignum.c | 382 ++++++++++++++++++++++++++-------------------- compar.c | 2 +- gc.c | 4 +- include/ruby/intern.h | 1 + include/ruby/ruby.h | 34 ++++- marshal.c | 18 +-- numeric.c | 2 +- random.c | 38 ++--- sprintf.c | 6 +- test/ruby/test_integer.rb | 12 ++ 12 files changed, 332 insertions(+), 203 deletions(-) diff --git a/.gdbinit b/.gdbinit index f54a38fb16..c7bddbd610 100644 --- a/.gdbinit +++ b/.gdbinit @@ -95,9 +95,17 @@ define rp 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: " diff --git a/ChangeLog b/ChangeLog index 4e2abeb831..b8803fef9b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +Sat Sep 1 20:56:07 2007 Tanaka Akira + + * include/ruby/ruby.h (struct RBignum): embed digits in RBignum for + small bignums. + + * bignum.c: RBignum embeded digits implemented. + + * include/ruby/intern.h: declare rb_big_resize. + + * gc.c: don't free embedded digits. + + * numeric.c: replace direct bignum field accessor by abstract field + accessor such as RBIGNUM(val)->sign to RBIGNUM_SIGN(val). + + * sprintf.c: ditto. + + * compar.c: ditto. + + * marshal.c: ditto. + + * random.c: ditto. + + * .gdbinit: support embedded small bignums. + Sat Sep 1 19:59:43 2007 Masaki Suketa * ext/win32ole/win32ole.c (ole_event_free): IConnectionPoint should be diff --git a/bignum.c b/bignum.c index c944907c64..8946748e0d 100644 --- a/bignum.c +++ b/bignum.c @@ -25,7 +25,7 @@ VALUE rb_cBignum; #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,68 @@ VALUE rb_cBignum; #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); + if (ds) { + 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 +108,9 @@ bignew_1(VALUE klass, long len, int sign) 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 +118,7 @@ rb_big_clone(VALUE x) static void get2comp(VALUE x) { - long i = RBIGNUM(x)->len; + long i = RBIGNUM_LEN(x); BDIGIT *ds = BDIGITS(x); BDIGIT_DBL num; @@ -77,11 +129,11 @@ get2comp(VALUE x) 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 +146,19 @@ rb_big_2comp(VALUE x) /* get 2's complement */ 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 +167,7 @@ bigfixize(VALUE x) 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 +210,7 @@ rb_uint2big(VALUE n) i = DIGSPERLONG; while (--i && !digits[i]) ; - RBIGNUM(big)->len = i+1; + RBIGNUM_SET_LEN(big, i+1); return big; } @@ -174,7 +226,7 @@ rb_int2big(SIGNED_VALUE n) } big = rb_uint2big(n); if (neg) { - RBIGNUM(big)->sign = 0; + RBIGNUM_SET_SIGN(big, 0); } return big; } @@ -205,7 +257,7 @@ rb_quad_pack(char *buf, VALUE val) 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 +269,7 @@ rb_quad_pack(char *buf, VALUE val) 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 +305,10 @@ rb_quad_unpack(const char *buf, int sign) 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 +327,12 @@ rb_quad_pack(char *buf, VALUE val) 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 +353,7 @@ rb_quad_unpack(const char *buf, int sign) 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 +501,7 @@ rb_cstr_to_inum(const char *str, int base, int badcheck) } else { VALUE big = rb_uint2big(val); - RBIGNUM(big)->sign = sign; + RBIGNUM_SET_SIGN(big, sign); return bignorm(big); } } @@ -546,7 +598,7 @@ rb_ull2big(unsigned LONG_LONG n) i = DIGSPERLL; while (i-- && !digits[i]) ; - RBIGNUM(big)->len = i+1; + RBIGNUM_SET_LEN(big, i+1); return big; } @@ -562,7 +614,7 @@ rb_ll2big(LONG_LONG n) } big = rb_ull2big(n); if (neg) { - RBIGNUM(big)->sign = 0; + RBIGNUM_SET_SIGN(big, 0); } return big; } @@ -722,7 +774,7 @@ power_cache_get_power(int base, long n1, long* m1) * 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. + * 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^(B*n_0) <= {b_1}^{2*n_1}, where b_1 is a @@ -759,7 +811,7 @@ big2str_find_n1(VALUE x, int base) return 0; } else { - bits = BITSPERDIG*RBIGNUM(x)->len; + bits = BITSPERDIG*RBIGNUM_LEN(x); } return (long)ceil(bits/(2*log_2[base - 2])); @@ -768,7 +820,7 @@ big2str_find_n1(VALUE x, int base) 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 +914,15 @@ rb_big2str0(VALUE x, int base, int trim) n1 = big2str_find_n1(x, base); ss = rb_str_new(0, 2*n1 + 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 +972,7 @@ rb_big_to_s(int argc, VALUE *argv, VALUE x) 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 +994,7 @@ VALUE 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 +1005,7 @@ rb_big2ulong(VALUE x) { 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 +1020,10 @@ rb_big2long(VALUE x) 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 +1032,7 @@ rb_big2long(VALUE x) 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 +1052,7 @@ rb_big2ull(VALUE x) { 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 +1061,11 @@ rb_big2ll(VALUE x) { 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 +1113,13 @@ static double 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 +1163,7 @@ rb_big_to_f(VALUE x) 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 +1180,18 @@ rb_big_cmp(VALUE x, VALUE y) 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 +1226,9 @@ rb_big_eq(VALUE x, VALUE y) 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 +1247,9 @@ static VALUE 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 +1265,7 @@ rb_big_uminus(VALUE x) { VALUE z = rb_big_clone(x); - RBIGNUM(z)->sign = !RBIGNUM(x)->sign; + RBIGNUM_SET_SIGN(z, !RBIGNUM_SIGN(x)); return bignorm(z); } @@ -1237,15 +1289,15 @@ rb_big_neg(VALUE x) 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 +1308,13 @@ bigsub(VALUE x, VALUE y) 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 +1327,20 @@ bigsub(VALUE x, VALUE y) } } - 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 +1355,28 @@ bigadd(VALUE x, VALUE y, int sign) 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 +1464,15 @@ rb_big_mul0(VALUE x, VALUE y) 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 +1501,7 @@ rb_big_mul(VALUE x, VALUE y) 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 +1527,15 @@ bigdivrem(VALUE x, VALUE y, VALUE *divp, VALUE *modp) 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 +1606,7 @@ bigdivrem(VALUE x, VALUE y, VALUE *divp, VALUE *modp) 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 +1621,8 @@ bigdivrem(VALUE x, VALUE y, VALUE *divp, VALUE *modp) 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 +1632,7 @@ bigdivmod(VALUE x, VALUE y, VALUE *divp, VALUE *modp) 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 +1819,8 @@ rb_big_quo(VALUE x, VALUE y) 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 +1828,8 @@ rb_big_quo(VALUE x, VALUE y) 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 +1864,7 @@ rb_big_quo(VALUE x, VALUE y) 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 +1879,30 @@ bigsqr(VALUE x) 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 +1945,8 @@ rb_big_pow(VALUE x, VALUE y) 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 +1988,29 @@ rb_big_and(VALUE xx, VALUE yy) 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; isign) get2comp(z); + if (!RBIGNUM_SIGN(z)) get2comp(z); return bignorm(z); } @@ -1988,29 +2044,29 @@ rb_big_or(VALUE xx, VALUE yy) 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; isign) get2comp(z); + if (!RBIGNUM_SIGN(z)) get2comp(z); return bignorm(z); } @@ -2046,31 +2102,31 @@ rb_big_xor(VALUE xx, VALUE yy) 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; isign) get2comp(z); + if (!RBIGNUM_SIGN(z)) get2comp(z); return bignorm(z); } @@ -2087,9 +2143,9 @@ rb_big_xor(VALUE xx, VALUE yy) 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 +2173,7 @@ rb_big_lshift(VALUE x, VALUE y) 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 +2198,8 @@ big_lshift(VALUE x, unsigned long shift) 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; isign) { + if (RBIGNUM_SIGN(y)) { VALUE t = check_shiftdown(y, x); if (!NIL_P(t)) return t; } @@ -2209,24 +2265,24 @@ big_rshift(VALUE x, unsigned long shift) 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 +2291,7 @@ big_rshift(VALUE x, unsigned long shift) zds[j] = BIGLO(num); num = BIGUP(xds[i]); } - if (!RBIGNUM(x)->sign) { + if (!RBIGNUM_SIGN(x)) { get2comp(z); } return bignorm(z); @@ -2269,11 +2325,11 @@ rb_big_aref(VALUE x, VALUE y) 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 +2341,8 @@ rb_big_aref(VALUE x, VALUE y) 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 +2369,7 @@ rb_big_hash(VALUE x) { 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 +2406,9 @@ rb_big_coerce(VALUE x, VALUE y) 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 +2428,7 @@ rb_big_abs(VALUE x) static VALUE rb_big_size(VALUE big) { - return LONG2FIX(RBIGNUM(big)->len*SIZEOF_BDIGITS); + return LONG2FIX(RBIGNUM_LEN(big)*SIZEOF_BDIGITS); } /* diff --git a/compar.c b/compar.c index a8952b2d1c..c1eb2d2861 100644 --- a/compar.c +++ b/compar.c @@ -24,7 +24,7 @@ rb_cmpint(VALUE val, VALUE a, VALUE b) } 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; diff --git a/gc.c b/gc.c index 7d521eb07a..c107c4e956 100644 --- a/gc.c +++ b/gc.c @@ -1311,8 +1311,8 @@ obj_free(VALUE obj) 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: diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 829d732893..e3776b8c6b 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -77,6 +77,7 @@ VALUE rb_get_values_at(VALUE, long, int, VALUE*, VALUE(*)(VALUE,long)); 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); diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index bf5804f647..5ccf246734 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -547,12 +547,38 @@ struct RStruct { 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)) @@ -631,6 +657,8 @@ enum ruby_value_flags { #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)) diff --git a/marshal.c b/marshal.c index 79e559d7f3..f634e3f264 100644 --- a/marshal.c +++ b/marshal.c @@ -514,9 +514,9 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) 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 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) 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; diff --git a/numeric.c b/numeric.c index 19e354709e..21d339a25c 100644 --- a/numeric.c +++ b/numeric.c @@ -2684,7 +2684,7 @@ fix_aref(VALUE fix, VALUE idx) 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); } diff --git a/random.c b/random.c index 077415420f..7cb0e12171 100644 --- a/random.c +++ b/random.c @@ -204,7 +204,7 @@ rand_init(VALUE vseed) 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 @@ rand_init(VALUE vseed) } 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 @@ random_seed(void) 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 @@ random_seed(void) 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 @@ limited_big_rand(struct RBignum *limit) 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 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj) 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)) { diff --git a/sprintf.c b/sprintf.c index 7fbfe1b391..f9b3d568e4 100644 --- a/sprintf.c +++ b/sprintf.c @@ -658,11 +658,11 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) } 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 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) else { char c; - if (!sign && bignum && !RBIGNUM(val)->sign) + if (!sign && bignum && !RBIGNUM_SIGN(val)) c = sign_bits(base, p); else c = '0'; diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index e62d503aec..b97ada8fc1 100644 --- a/test/ruby/test_integer.rb +++ b/test/ruby/test_integer.rb @@ -2,6 +2,12 @@ require 'test/unit' class TestInteger < Test::Unit::TestCase VS = [ + -0x1000000000000000000000000000000000000000000000002, + -0x1000000000000000000000000000000000000000000000001, + -0x1000000000000000000000000000000000000000000000000, + -0x1000000000000000000000002, + -0x1000000000000000000000001, + -0x1000000000000000000000000, -0x10000000000000002, -0x10000000000000001, -0x10000000000000000, @@ -89,6 +95,12 @@ class TestInteger < Test::Unit::TestCase 0xffffffffffffffff, 0x10000000000000000, 0x10000000000000001, + 0xffffffffffffffffffffffff, + 0x1000000000000000000000000, + 0x1000000000000000000000001, + 0xffffffffffffffffffffffffffffffffffffffffffffffff, + 0x1000000000000000000000000000000000000000000000000, + 0x1000000000000000000000000000000000000000000000001 ] #VS.map! {|v| 0x4000000000000000.coerce(v)[0] } -- cgit v1.2.3