bignum.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   bignum.c -
00004 
00005   $Author: yugui $
00006   created at: Fri Jun 10 00:48:55 JST 1994
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009 
00010 **********************************************************************/
00011 
00012 #include "ruby/ruby.h"
00013 #include "ruby/util.h"
00014 
00015 #include <math.h>
00016 #include <float.h>
00017 #include <ctype.h>
00018 #ifdef HAVE_IEEEFP_H
00019 #include <ieeefp.h>
00020 #endif
00021 #include <assert.h>
00022 
00023 VALUE rb_cBignum;
00024 
00025 #if defined __MINGW32__
00026 #define USHORT _USHORT
00027 #endif
00028 
00029 #define BDIGITS(x) (RBIGNUM_DIGITS(x))
00030 #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
00031 #define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
00032 #define DIGSPERLONG (SIZEOF_LONG/SIZEOF_BDIGITS)
00033 #if HAVE_LONG_LONG
00034 # define DIGSPERLL (SIZEOF_LONG_LONG/SIZEOF_BDIGITS)
00035 #endif
00036 #define BIGUP(x) ((BDIGIT_DBL)(x) << BITSPERDIG)
00037 #define BIGDN(x) RSHIFT(x,BITSPERDIG)
00038 #define BIGLO(x) ((BDIGIT)((x) & (BIGRAD-1)))
00039 #define BDIGMAX ((BDIGIT)-1)
00040 
00041 #define BIGZEROP(x) (RBIGNUM_LEN(x) == 0 || \
00042                      (BDIGITS(x)[0] == 0 && \
00043                       (RBIGNUM_LEN(x) == 1 || bigzero_p(x))))
00044 
00045 static int
00046 bigzero_p(VALUE x)
00047 {
00048     long i;
00049     BDIGIT *ds = BDIGITS(x);
00050 
00051     for (i = RBIGNUM_LEN(x) - 1; 0 <= i; i--) {
00052         if (ds[i]) return 0;
00053     }
00054     return 1;
00055 }
00056 
00057 int
00058 rb_bigzero_p(VALUE x)
00059 {
00060     return BIGZEROP(x);
00061 }
00062 
00063 int
00064 rb_cmpint(VALUE val, VALUE a, VALUE b)
00065 {
00066     if (NIL_P(val)) {
00067         rb_cmperr(a, b);
00068     }
00069     if (FIXNUM_P(val)) {
00070         long l = FIX2LONG(val);
00071         if (l > 0) return 1;
00072         if (l < 0) return -1;
00073         return 0;
00074     }
00075     if (TYPE(val) == T_BIGNUM) {
00076         if (BIGZEROP(val)) return 0;
00077         if (RBIGNUM_SIGN(val)) return 1;
00078         return -1;
00079     }
00080     if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1;
00081     if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1;
00082     return 0;
00083 }
00084 
00085 #define RBIGNUM_SET_LEN(b,l) \
00086     ((RBASIC(b)->flags & RBIGNUM_EMBED_FLAG) ? \
00087      (void)(RBASIC(b)->flags = \
00088             (RBASIC(b)->flags & ~RBIGNUM_EMBED_LEN_MASK) | \
00089             ((l) << RBIGNUM_EMBED_LEN_SHIFT)) : \
00090      (void)(RBIGNUM(b)->as.heap.len = (l)))
00091 
00092 static void
00093 rb_big_realloc(VALUE big, long len)
00094 {
00095     BDIGIT *ds;
00096     if (RBASIC(big)->flags & RBIGNUM_EMBED_FLAG) {
00097         if (RBIGNUM_EMBED_LEN_MAX < len) {
00098             ds = ALLOC_N(BDIGIT, len);
00099             MEMCPY(ds, RBIGNUM(big)->as.ary, BDIGIT, RBIGNUM_EMBED_LEN_MAX);
00100             RBIGNUM(big)->as.heap.len = RBIGNUM_LEN(big);
00101             RBIGNUM(big)->as.heap.digits = ds;
00102             RBASIC(big)->flags &= ~RBIGNUM_EMBED_FLAG;
00103         }
00104     }
00105     else {
00106         if (len <= RBIGNUM_EMBED_LEN_MAX) {
00107             ds = RBIGNUM(big)->as.heap.digits;
00108             RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
00109             RBIGNUM_SET_LEN(big, len);
00110             if (ds) {
00111                 MEMCPY(RBIGNUM(big)->as.ary, ds, BDIGIT, len);
00112                 xfree(ds);
00113             }
00114         }
00115         else {
00116             if (RBIGNUM_LEN(big) == 0) {
00117                 RBIGNUM(big)->as.heap.digits = ALLOC_N(BDIGIT, len);
00118             }
00119             else {
00120                 REALLOC_N(RBIGNUM(big)->as.heap.digits, BDIGIT, len);
00121             }
00122         }
00123     }
00124 }
00125 
00126 void
00127 rb_big_resize(VALUE big, long len)
00128 {
00129     rb_big_realloc(big, len);
00130     RBIGNUM_SET_LEN(big, len);
00131 }
00132 
00133 static VALUE
00134 bignew_1(VALUE klass, long len, int sign)
00135 {
00136     NEWOBJ(big, struct RBignum);
00137     OBJSETUP(big, klass, T_BIGNUM);
00138     RBIGNUM_SET_SIGN(big, sign?1:0);
00139     if (len <= RBIGNUM_EMBED_LEN_MAX) {
00140         RBASIC(big)->flags |= RBIGNUM_EMBED_FLAG;
00141         RBIGNUM_SET_LEN(big, len);
00142     }
00143     else {
00144         RBIGNUM(big)->as.heap.digits = ALLOC_N(BDIGIT, len);
00145         RBIGNUM(big)->as.heap.len = len;
00146     }
00147 
00148     return (VALUE)big;
00149 }
00150 
00151 #define bignew(len,sign) bignew_1(rb_cBignum,len,sign)
00152 
00153 VALUE
00154 rb_big_new(long len, int sign)
00155 {
00156     return bignew(len, sign != 0);
00157 }
00158 
00159 VALUE
00160 rb_big_clone(VALUE x)
00161 {
00162     long len = RBIGNUM_LEN(x);
00163     VALUE z = bignew_1(CLASS_OF(x), len, RBIGNUM_SIGN(x));
00164 
00165     MEMCPY(BDIGITS(z), BDIGITS(x), BDIGIT, len);
00166     return z;
00167 }
00168 
00169 /* modify a bignum by 2's complement */
00170 static void
00171 get2comp(VALUE x)
00172 {
00173     long i = RBIGNUM_LEN(x);
00174     BDIGIT *ds = BDIGITS(x);
00175     BDIGIT_DBL num;
00176 
00177     if (!i) return;
00178     while (i--) ds[i] = ~ds[i];
00179     i = 0; num = 1;
00180     do {
00181         num += ds[i];
00182         ds[i++] = BIGLO(num);
00183         num = BIGDN(num);
00184     } while (i < RBIGNUM_LEN(x));
00185     if (num != 0) {
00186         rb_big_resize(x, RBIGNUM_LEN(x)+1);
00187         ds = BDIGITS(x);
00188         ds[RBIGNUM_LEN(x)-1] = 1;
00189     }
00190 }
00191 
00192 void
00193 rb_big_2comp(VALUE x)                   /* get 2's complement */
00194 {
00195     get2comp(x);
00196 }
00197 
00198 static inline VALUE
00199 bigtrunc(VALUE x)
00200 {
00201     long len = RBIGNUM_LEN(x);
00202     BDIGIT *ds = BDIGITS(x);
00203 
00204     if (len == 0) return x;
00205     while (--len && !ds[len]);
00206     if (RBIGNUM_LEN(x) > len+1) {
00207         rb_big_resize(x, len+1);
00208     }
00209     return x;
00210 }
00211 
00212 static inline VALUE
00213 bigfixize(VALUE x)
00214 {
00215     long len = RBIGNUM_LEN(x);
00216     BDIGIT *ds = BDIGITS(x);
00217 
00218     if (len == 0) return INT2FIX(0);
00219     if ((size_t)(len*SIZEOF_BDIGITS) <= sizeof(long)) {
00220         long num = 0;
00221 #if 2*SIZEOF_BDIGITS > SIZEOF_LONG
00222         num = (long)ds[0];
00223 #else
00224         while (len--) {
00225             num = (long)(BIGUP(num) + ds[len]);
00226         }
00227 #endif
00228         if (num >= 0) {
00229             if (RBIGNUM_SIGN(x)) {
00230                 if (POSFIXABLE(num)) return LONG2FIX(num);
00231             }
00232             else {
00233                 if (NEGFIXABLE(-num)) return LONG2FIX(-num);
00234             }
00235         }
00236     }
00237     return x;
00238 }
00239 
00240 static VALUE
00241 bignorm(VALUE x)
00242 {
00243     if (!FIXNUM_P(x) && TYPE(x) == T_BIGNUM) {
00244         x = bigfixize(bigtrunc(x));
00245     }
00246     return x;
00247 }
00248 
00249 VALUE
00250 rb_big_norm(VALUE x)
00251 {
00252     return bignorm(x);
00253 }
00254 
00255 VALUE
00256 rb_uint2big(VALUE n)
00257 {
00258     BDIGIT_DBL num = n;
00259     long i = 0;
00260     BDIGIT *digits;
00261     VALUE big;
00262 
00263     big = bignew(DIGSPERLONG, 1);
00264     digits = BDIGITS(big);
00265     while (i < DIGSPERLONG) {
00266         digits[i++] = BIGLO(num);
00267         num = BIGDN(num);
00268     }
00269 
00270     i = DIGSPERLONG;
00271     while (--i && !digits[i]) ;
00272     RBIGNUM_SET_LEN(big, i+1);
00273     return big;
00274 }
00275 
00276 VALUE
00277 rb_int2big(SIGNED_VALUE n)
00278 {
00279     long neg = 0;
00280     VALUE big;
00281 
00282     if (n < 0) {
00283         n = -n;
00284         neg = 1;
00285     }
00286     big = rb_uint2big(n);
00287     if (neg) {
00288         RBIGNUM_SET_SIGN(big, 0);
00289     }
00290     return big;
00291 }
00292 
00293 VALUE
00294 rb_uint2inum(VALUE n)
00295 {
00296     if (POSFIXABLE(n)) return LONG2FIX(n);
00297     return rb_uint2big(n);
00298 }
00299 
00300 VALUE
00301 rb_int2inum(SIGNED_VALUE n)
00302 {
00303     if (FIXABLE(n)) return LONG2FIX(n);
00304     return rb_int2big(n);
00305 }
00306 
00307 #if SIZEOF_LONG % SIZEOF_BDIGITS != 0
00308 # error unexpected SIZEOF_LONG : SIZEOF_BDIGITS ratio
00309 #endif
00310 
00311 /*
00312  * buf is an array of long integers.
00313  * buf is ordered from least significant word to most significant word.
00314  * buf[0] is the least significant word and
00315  * buf[num_longs-1] is the most significant word.
00316  * This means words in buf is little endian.
00317  * However each word in buf is native endian.
00318  * (buf[i]&1) is the least significant bit and
00319  * (buf[i]&(1<<(SIZEOF_LONG*CHAR_BIT-1))) is the most significant bit
00320  * for each 0 <= i < num_longs.
00321  * So buf is little endian at whole on a little endian machine.
00322  * But buf is mixed endian on a big endian machine.
00323  */
00324 void
00325 rb_big_pack(VALUE val, unsigned long *buf, long num_longs)
00326 {
00327     val = rb_to_int(val);
00328     if (num_longs == 0)
00329         return;
00330     if (FIXNUM_P(val)) {
00331         long i;
00332         long tmp = FIX2LONG(val);
00333         buf[0] = (unsigned long)tmp;
00334         tmp = tmp < 0 ? ~0L : 0;
00335         for (i = 1; i < num_longs; i++)
00336             buf[i] = (unsigned long)tmp;
00337         return;
00338     }
00339     else {
00340         long len = RBIGNUM_LEN(val);
00341         BDIGIT *ds = BDIGITS(val), *dend = ds + len;
00342         long i, j;
00343         for (i = 0; i < num_longs && ds < dend; i++) {
00344             unsigned long l = 0;
00345             for (j = 0; j < DIGSPERLONG && ds < dend; j++, ds++) {
00346                 l |= ((unsigned long)*ds << (j * BITSPERDIG));
00347             }
00348             buf[i] = l;
00349         }
00350         for (; i < num_longs; i++)
00351             buf[i] = 0;
00352         if (RBIGNUM_NEGATIVE_P(val)) {
00353             for (i = 0; i < num_longs; i++) {
00354                 buf[i] = ~buf[i];
00355             }
00356             for (i = 0; i < num_longs; i++) {
00357                 buf[i]++;
00358                 if (buf[i] != 0)
00359                     return;
00360             }
00361         }
00362     }
00363 }
00364 
00365 /* See rb_big_pack comment for endianness of buf. */
00366 VALUE
00367 rb_big_unpack(unsigned long *buf, long num_longs)
00368 {
00369     while (2 <= num_longs) {
00370         if (buf[num_longs-1] == 0 && (long)buf[num_longs-2] >= 0)
00371             num_longs--;
00372         else if (buf[num_longs-1] == ~0UL && (long)buf[num_longs-2] < 0)
00373             num_longs--;
00374         else
00375             break;
00376     }
00377     if (num_longs == 0)
00378         return INT2FIX(0);
00379     else if (num_longs == 1)
00380         return LONG2NUM((long)buf[0]);
00381     else {
00382         VALUE big;
00383         BDIGIT *ds;
00384         long len = num_longs * DIGSPERLONG;
00385         long i;
00386         big = bignew(len, 1);
00387         ds = BDIGITS(big);
00388         for (i = 0; i < num_longs; i++) {
00389             unsigned long d = buf[i];
00390 #if SIZEOF_LONG == SIZEOF_BDIGITS
00391             *ds++ = d;
00392 #else
00393             int j;
00394             for (j = 0; j < DIGSPERLONG; j++) {
00395                 *ds++ = BIGLO(d);
00396                 d = BIGDN(d);
00397             }
00398 #endif
00399         }
00400         if ((long)buf[num_longs-1] < 0) {
00401             get2comp(big);
00402             RBIGNUM_SET_SIGN(big, 0);
00403         }
00404         return bignorm(big);
00405     }
00406 }
00407 
00408 #define QUAD_SIZE 8
00409 
00410 #if SIZEOF_LONG_LONG == QUAD_SIZE && SIZEOF_BDIGITS*2 == SIZEOF_LONG_LONG
00411 
00412 void
00413 rb_quad_pack(char *buf, VALUE val)
00414 {
00415     LONG_LONG q;
00416 
00417     val = rb_to_int(val);
00418     if (FIXNUM_P(val)) {
00419         q = FIX2LONG(val);
00420     }
00421     else {
00422         long len = RBIGNUM_LEN(val);
00423         BDIGIT *ds;
00424 
00425         if (len > SIZEOF_LONG_LONG/SIZEOF_BDIGITS) {
00426             len = SIZEOF_LONG_LONG/SIZEOF_BDIGITS;
00427         }
00428         ds = BDIGITS(val);
00429         q = 0;
00430         while (len--) {
00431             q = BIGUP(q);
00432             q += ds[len];
00433         }
00434         if (!RBIGNUM_SIGN(val)) q = -q;
00435     }
00436     memcpy(buf, (char*)&q, SIZEOF_LONG_LONG);
00437 }
00438 
00439 VALUE
00440 rb_quad_unpack(const char *buf, int sign)
00441 {
00442     unsigned LONG_LONG q;
00443     long neg = 0;
00444     long i;
00445     BDIGIT *digits;
00446     VALUE big;
00447 
00448     memcpy(&q, buf, SIZEOF_LONG_LONG);
00449     if (sign) {
00450         if (FIXABLE((LONG_LONG)q)) return LONG2FIX((LONG_LONG)q);
00451         if ((LONG_LONG)q < 0) {
00452             q = -(LONG_LONG)q;
00453             neg = 1;
00454         }
00455     }
00456     else {
00457         if (POSFIXABLE(q)) return LONG2FIX(q);
00458     }
00459 
00460     i = 0;
00461     big = bignew(DIGSPERLL, 1);
00462     digits = BDIGITS(big);
00463     while (i < DIGSPERLL) {
00464         digits[i++] = BIGLO(q);
00465         q = BIGDN(q);
00466     }
00467 
00468     i = DIGSPERLL;
00469     while (i-- && !digits[i]) ;
00470     RBIGNUM_SET_LEN(big, i+1);
00471 
00472     if (neg) {
00473         RBIGNUM_SET_SIGN(big, 0);
00474     }
00475     return bignorm(big);
00476 }
00477 
00478 #else
00479 
00480 static int
00481 quad_buf_complement(char *buf, size_t len)
00482 {
00483     size_t i;
00484     for (i = 0; i < len; i++)
00485         buf[i] = ~buf[i];
00486     for (i = 0; i < len; i++) {
00487         buf[i]++;
00488         if (buf[i] != 0)
00489             return 0;
00490     }
00491     return 1;
00492 }
00493 
00494 void
00495 rb_quad_pack(char *buf, VALUE val)
00496 {
00497     long len;
00498 
00499     memset(buf, 0, QUAD_SIZE);
00500     val = rb_to_int(val);
00501     if (FIXNUM_P(val)) {
00502         val = rb_int2big(FIX2LONG(val));
00503     }
00504     len = RBIGNUM_LEN(val) * SIZEOF_BDIGITS;
00505     if (len > QUAD_SIZE) {
00506         len = QUAD_SIZE;
00507     }
00508     memcpy(buf, (char*)BDIGITS(val), len);
00509     if (RBIGNUM_NEGATIVE_P(val)) {
00510         quad_buf_complement(buf, QUAD_SIZE);
00511     }
00512 }
00513 
00514 #define BNEG(b) (RSHIFT(((BDIGIT*)b)[QUAD_SIZE/SIZEOF_BDIGITS-1],BITSPERDIG-1) != 0)
00515 
00516 VALUE
00517 rb_quad_unpack(const char *buf, int sign)
00518 {
00519     VALUE big = bignew(QUAD_SIZE/SIZEOF_BDIGITS, 1);
00520 
00521     memcpy((char*)BDIGITS(big), buf, QUAD_SIZE);
00522     if (sign && BNEG(buf)) {
00523         char *tmp = (char*)BDIGITS(big);
00524 
00525         RBIGNUM_SET_SIGN(big, 0);
00526         quad_buf_complement(tmp, QUAD_SIZE);
00527     }
00528 
00529     return bignorm(big);
00530 }
00531 
00532 #endif
00533 
00534 VALUE
00535 rb_cstr_to_inum(const char *str, int base, int badcheck)
00536 {
00537     const char *s = str;
00538     char *end;
00539     char sign = 1, nondigit = 0;
00540     int c;
00541     BDIGIT_DBL num;
00542     long len, blen = 1;
00543     long i;
00544     VALUE z;
00545     BDIGIT *zds;
00546 
00547 #undef ISDIGIT
00548 #define ISDIGIT(c) ('0' <= (c) && (c) <= '9')
00549 #define conv_digit(c) \
00550     (!ISASCII(c) ? -1 : \
00551      ISDIGIT(c) ? ((c) - '0') : \
00552      ISLOWER(c) ? ((c) - 'a' + 10) : \
00553      ISUPPER(c) ? ((c) - 'A' + 10) : \
00554      -1)
00555 
00556     if (!str) {
00557         if (badcheck) goto bad;
00558         return INT2FIX(0);
00559     }
00560     while (ISSPACE(*str)) str++;
00561 
00562     if (str[0] == '+') {
00563         str++;
00564     }
00565     else if (str[0] == '-') {
00566         str++;
00567         sign = 0;
00568     }
00569     if (str[0] == '+' || str[0] == '-') {
00570         if (badcheck) goto bad;
00571         return INT2FIX(0);
00572     }
00573     if (base <= 0) {
00574         if (str[0] == '0') {
00575             switch (str[1]) {
00576               case 'x': case 'X':
00577                 base = 16;
00578                 break;
00579               case 'b': case 'B':
00580                 base = 2;
00581                 break;
00582               case 'o': case 'O':
00583                 base = 8;
00584                 break;
00585               case 'd': case 'D':
00586                 base = 10;
00587                 break;
00588               default:
00589                 base = 8;
00590             }
00591         }
00592         else if (base < -1) {
00593             base = -base;
00594         }
00595         else {
00596             base = 10;
00597         }
00598     }
00599     switch (base) {
00600       case 2:
00601         len = 1;
00602         if (str[0] == '0' && (str[1] == 'b'||str[1] == 'B')) {
00603             str += 2;
00604         }
00605         break;
00606       case 3:
00607         len = 2;
00608         break;
00609       case 8:
00610         if (str[0] == '0' && (str[1] == 'o'||str[1] == 'O')) {
00611             str += 2;
00612         }
00613       case 4: case 5: case 6: case 7:
00614         len = 3;
00615         break;
00616       case 10:
00617         if (str[0] == '0' && (str[1] == 'd'||str[1] == 'D')) {
00618             str += 2;
00619         }
00620       case 9: case 11: case 12: case 13: case 14: case 15:
00621         len = 4;
00622         break;
00623       case 16:
00624         len = 4;
00625         if (str[0] == '0' && (str[1] == 'x'||str[1] == 'X')) {
00626             str += 2;
00627         }
00628         break;
00629       default:
00630         if (base < 2 || 36 < base) {
00631             rb_raise(rb_eArgError, "invalid radix %d", base);
00632         }
00633         if (base <= 32) {
00634             len = 5;
00635         }
00636         else {
00637             len = 6;
00638         }
00639         break;
00640     }
00641     if (*str == '0') {          /* squeeze preceding 0s */
00642         int us = 0;
00643         while ((c = *++str) == '0' || c == '_') {
00644             if (c == '_') {
00645                 if (++us >= 2)
00646                     break;
00647             } else
00648                 us = 0;
00649         }
00650         if (!(c = *str) || ISSPACE(c)) --str;
00651     }
00652     c = *str;
00653     c = conv_digit(c);
00654     if (c < 0 || c >= base) {
00655         if (badcheck) goto bad;
00656         return INT2FIX(0);
00657     }
00658     len *= strlen(str)*sizeof(char);
00659 
00660     if ((size_t)len <= (sizeof(long)*CHAR_BIT)) {
00661         unsigned long val = STRTOUL(str, &end, base);
00662 
00663         if (str < end && *end == '_') goto bigparse;
00664         if (badcheck) {
00665             if (end == str) goto bad; /* no number */
00666             while (*end && ISSPACE(*end)) end++;
00667             if (*end) goto bad;       /* trailing garbage */
00668         }
00669 
00670         if (POSFIXABLE(val)) {
00671             if (sign) return LONG2FIX(val);
00672             else {
00673                 long result = -(long)val;
00674                 return LONG2FIX(result);
00675             }
00676         }
00677         else {
00678             VALUE big = rb_uint2big(val);
00679             RBIGNUM_SET_SIGN(big, sign);
00680             return bignorm(big);
00681         }
00682     }
00683   bigparse:
00684     len = (len/BITSPERDIG)+1;
00685     if (badcheck && *str == '_') goto bad;
00686 
00687     z = bignew(len, sign);
00688     zds = BDIGITS(z);
00689     for (i=len;i--;) zds[i]=0;
00690     while ((c = *str++) != 0) {
00691         if (c == '_') {
00692             if (nondigit) {
00693                 if (badcheck) goto bad;
00694                 break;
00695             }
00696             nondigit = c;
00697             continue;
00698         }
00699         else if ((c = conv_digit(c)) < 0) {
00700             break;
00701         }
00702         if (c >= base) break;
00703         nondigit = 0;
00704         i = 0;
00705         num = c;
00706         for (;;) {
00707             while (i<blen) {
00708                 num += (BDIGIT_DBL)zds[i]*base;
00709                 zds[i++] = BIGLO(num);
00710                 num = BIGDN(num);
00711             }
00712             if (num) {
00713                 blen++;
00714                 continue;
00715             }
00716             break;
00717         }
00718     }
00719     if (badcheck) {
00720         str--;
00721         if (s+1 < str && str[-1] == '_') goto bad;
00722         while (*str && ISSPACE(*str)) str++;
00723         if (*str) {
00724           bad:
00725             rb_invalid_str(s, "Integer()");
00726         }
00727     }
00728 
00729     return bignorm(z);
00730 }
00731 
00732 VALUE
00733 rb_str_to_inum(VALUE str, int base, int badcheck)
00734 {
00735     char *s;
00736     long len;
00737 
00738     StringValue(str);
00739     if (badcheck) {
00740         s = StringValueCStr(str);
00741     }
00742     else {
00743         s = RSTRING_PTR(str);
00744     }
00745     if (s) {
00746         len = RSTRING_LEN(str);
00747         if (s[len]) {           /* no sentinel somehow */
00748             char *p = ALLOCA_N(char, len+1);
00749 
00750             MEMCPY(p, s, char, len);
00751             p[len] = '\0';
00752             s = p;
00753         }
00754     }
00755     return rb_cstr_to_inum(s, base, badcheck);
00756 }
00757 
00758 #if HAVE_LONG_LONG
00759 
00760 static VALUE
00761 rb_ull2big(unsigned LONG_LONG n)
00762 {
00763     BDIGIT_DBL num = n;
00764     long i = 0;
00765     BDIGIT *digits;
00766     VALUE big;
00767 
00768     big = bignew(DIGSPERLL, 1);
00769     digits = BDIGITS(big);
00770     while (i < DIGSPERLL) {
00771         digits[i++] = BIGLO(num);
00772         num = BIGDN(num);
00773     }
00774 
00775     i = DIGSPERLL;
00776     while (i-- && !digits[i]) ;
00777     RBIGNUM_SET_LEN(big, i+1);
00778     return big;
00779 }
00780 
00781 static VALUE
00782 rb_ll2big(LONG_LONG n)
00783 {
00784     long neg = 0;
00785     VALUE big;
00786 
00787     if (n < 0) {
00788         n = -n;
00789         neg = 1;
00790     }
00791     big = rb_ull2big(n);
00792     if (neg) {
00793         RBIGNUM_SET_SIGN(big, 0);
00794     }
00795     return big;
00796 }
00797 
00798 VALUE
00799 rb_ull2inum(unsigned LONG_LONG n)
00800 {
00801     if (POSFIXABLE(n)) return LONG2FIX(n);
00802     return rb_ull2big(n);
00803 }
00804 
00805 VALUE
00806 rb_ll2inum(LONG_LONG n)
00807 {
00808     if (FIXABLE(n)) return LONG2FIX(n);
00809     return rb_ll2big(n);
00810 }
00811 
00812 #endif  /* HAVE_LONG_LONG */
00813 
00814 VALUE
00815 rb_cstr2inum(const char *str, int base)
00816 {
00817     return rb_cstr_to_inum(str, base, base==0);
00818 }
00819 
00820 VALUE
00821 rb_str2inum(VALUE str, int base)
00822 {
00823     return rb_str_to_inum(str, base, base==0);
00824 }
00825 
00826 const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00827 
00828 static VALUE bigsqr(VALUE x);
00829 static void bigdivmod(VALUE x, VALUE y, volatile VALUE *divp, volatile VALUE *modp);
00830 
00831 #define POW2_P(x) (((x)&((x)-1))==0)
00832 
00833 static inline int
00834 ones(register unsigned long x)
00835 {
00836 #if SIZEOF_LONG == 8
00837 # define MASK_55 0x5555555555555555UL
00838 # define MASK_33 0x3333333333333333UL
00839 # define MASK_0f 0x0f0f0f0f0f0f0f0fUL
00840 #else
00841 # define MASK_55 0x55555555UL
00842 # define MASK_33 0x33333333UL
00843 # define MASK_0f 0x0f0f0f0fUL
00844 #endif
00845     x -= (x >> 1) & MASK_55;
00846     x = ((x >> 2) & MASK_33) + (x & MASK_33);
00847     x = ((x >> 4) + x) & MASK_0f;
00848     x += (x >> 8);
00849     x += (x >> 16);
00850 #if SIZEOF_LONG == 8
00851     x += (x >> 32);
00852 #endif
00853     return (int)(x & 0x7f);
00854 #undef MASK_0f
00855 #undef MASK_33
00856 #undef MASK_55
00857 }
00858 
00859 static inline unsigned long
00860 next_pow2(register unsigned long x)
00861 {
00862     x |= x >> 1;
00863     x |= x >> 2;
00864     x |= x >> 4;
00865     x |= x >> 8;
00866     x |= x >> 16;
00867 #if SIZEOF_LONG == 8
00868     x |= x >> 32;
00869 #endif
00870     return x + 1;
00871 }
00872 
00873 static inline int
00874 floor_log2(register unsigned long x)
00875 {
00876     x |= x >> 1;
00877     x |= x >> 2;
00878     x |= x >> 4;
00879     x |= x >> 8;
00880     x |= x >> 16;
00881 #if SIZEOF_LONG == 8
00882     x |= x >> 32;
00883 #endif
00884     return (int)ones(x) - 1;
00885 }
00886 
00887 static inline int
00888 ceil_log2(register unsigned long x)
00889 {
00890     return floor_log2(x) + !POW2_P(x);
00891 }
00892 
00893 #define LOG2_KARATSUBA_DIGITS 7
00894 #define KARATSUBA_DIGITS (1L<<LOG2_KARATSUBA_DIGITS)
00895 #define MAX_BIG2STR_TABLE_ENTRIES 64
00896 
00897 static VALUE big2str_power_cache[35][MAX_BIG2STR_TABLE_ENTRIES];
00898 
00899 static void
00900 power_cache_init(void)
00901 {
00902     int i, j;
00903     for (i = 0; i < 35; ++i) {
00904         for (j = 0; j < MAX_BIG2STR_TABLE_ENTRIES; ++j) {
00905             big2str_power_cache[i][j] = Qnil;
00906         }
00907     }
00908 }
00909 
00910 static inline VALUE
00911 power_cache_get_power0(int base, int i)
00912 {
00913     if (NIL_P(big2str_power_cache[base - 2][i])) {
00914         big2str_power_cache[base - 2][i] =
00915             i == 0 ? rb_big_pow(rb_int2big(base), INT2FIX(KARATSUBA_DIGITS))
00916                    : bigsqr(power_cache_get_power0(base, i - 1));
00917         rb_gc_register_mark_object(big2str_power_cache[base - 2][i]);
00918     }
00919     return big2str_power_cache[base - 2][i];
00920 }
00921 
00922 static VALUE
00923 power_cache_get_power(int base, long n1, long* m1)
00924 {
00925     int i, m;
00926     long j;
00927     VALUE t;
00928 
00929     if (n1 <= KARATSUBA_DIGITS)
00930         rb_bug("n1 > KARATSUBA_DIGITS");
00931 
00932     m = ceil_log2(n1);
00933     if (m1) *m1 = 1 << m;
00934     i = m - LOG2_KARATSUBA_DIGITS;
00935     if (i >= MAX_BIG2STR_TABLE_ENTRIES)
00936         i = MAX_BIG2STR_TABLE_ENTRIES - 1;
00937     t = power_cache_get_power0(base, i);
00938 
00939     j = KARATSUBA_DIGITS*(1 << i);
00940     while (n1 > j) {
00941         t = bigsqr(t);
00942         j *= 2;
00943     }
00944     return t;
00945 }
00946 
00947 /* big2str_muraken_find_n1
00948  *
00949  * Let a natural number x is given by:
00950  * x = 2^0 * x_0 + 2^1 * x_1 + ... + 2^(B*n_0 - 1) * x_{B*n_0 - 1},
00951  * where B is BITSPERDIG (i.e. BDIGITS*CHAR_BIT) and n_0 is
00952  * RBIGNUM_LEN(x).
00953  *
00954  * Now, we assume n_1 = min_n \{ n | 2^(B*n_0/2) <= b_1^(n_1) \}, so
00955  * it is realized that 2^(B*n_0) <= {b_1}^{2*n_1}, where b_1 is a
00956  * given radix number. And then, we have n_1 <= (B*n_0) /
00957  * (2*log_2(b_1)), therefore n_1 is given by ceil((B*n_0) /
00958  * (2*log_2(b_1))).
00959  */
00960 static long
00961 big2str_find_n1(VALUE x, int base)
00962 {
00963     static const double log_2[] = {
00964         1.0,              1.58496250072116, 2.0,
00965         2.32192809488736, 2.58496250072116, 2.8073549220576,
00966         3.0,              3.16992500144231, 3.32192809488736,
00967         3.4594316186373,  3.58496250072116, 3.70043971814109,
00968         3.8073549220576,  3.90689059560852, 4.0,
00969         4.08746284125034, 4.16992500144231, 4.24792751344359,
00970         4.32192809488736, 4.39231742277876, 4.4594316186373,
00971         4.52356195605701, 4.58496250072116, 4.64385618977472,
00972         4.70043971814109, 4.75488750216347, 4.8073549220576,
00973         4.85798099512757, 4.90689059560852, 4.95419631038688,
00974         5.0,              5.04439411935845, 5.08746284125034,
00975         5.12928301694497, 5.16992500144231
00976     };
00977     long bits;
00978 
00979     if (base < 2 || 36 < base)
00980         rb_bug("invalid radix %d", base);
00981 
00982     if (FIXNUM_P(x)) {
00983         bits = (SIZEOF_LONG*CHAR_BIT - 1)/2 + 1;
00984     }
00985     else if (BIGZEROP(x)) {
00986         return 0;
00987     }
00988     else if (RBIGNUM_LEN(x) >= LONG_MAX/BITSPERDIG) {
00989         rb_raise(rb_eRangeError, "bignum too big to convert into `string'");
00990     }
00991     else {
00992         bits = BITSPERDIG*RBIGNUM_LEN(x);
00993     }
00994 
00995     return (long)ceil(bits/log_2[base - 2]);
00996 }
00997 
00998 static long
00999 big2str_orig(VALUE x, int base, char* ptr, long len, long hbase, int trim)
01000 {
01001     long i = RBIGNUM_LEN(x), j = len;
01002     BDIGIT* ds = BDIGITS(x);
01003 
01004     while (i && j > 0) {
01005         long k = i;
01006         BDIGIT_DBL num = 0;
01007 
01008         while (k--) {               /* x / hbase */
01009             num = BIGUP(num) + ds[k];
01010             ds[k] = (BDIGIT)(num / hbase);
01011             num %= hbase;
01012         }
01013         if (trim && ds[i-1] == 0) i--;
01014         k = SIZEOF_BDIGITS;
01015         while (k--) {
01016             ptr[--j] = ruby_digitmap[num % base];
01017             num /= base;
01018             if (j <= 0) break;
01019             if (trim && i == 0 && num == 0) break;
01020         }
01021     }
01022     if (trim) {
01023         while (j < len && ptr[j] == '0') j++;
01024         MEMMOVE(ptr, ptr + j, char, len - j);
01025         len -= j;
01026     }
01027     return len;
01028 }
01029 
01030 static long
01031 big2str_karatsuba(VALUE x, int base, char* ptr,
01032                   long n1, long len, long hbase, int trim)
01033 {
01034     long lh, ll, m1;
01035     VALUE b, q, r;
01036 
01037     if (BIGZEROP(x)) {
01038         if (trim) return 0;
01039         else {
01040             memset(ptr, '0', len);
01041             return len;
01042         }
01043     }
01044 
01045     if (n1 <= KARATSUBA_DIGITS) {
01046         return big2str_orig(x, base, ptr, len, hbase, trim);
01047     }
01048 
01049     b = power_cache_get_power(base, n1, &m1);
01050     bigdivmod(x, b, &q, &r);
01051     lh = big2str_karatsuba(q, base, ptr, (len - m1)/2,
01052                            len - m1, hbase, trim);
01053     rb_big_resize(q, 0);
01054     ll = big2str_karatsuba(r, base, ptr + lh, m1/2,
01055                            m1, hbase, !lh && trim);
01056     rb_big_resize(r, 0);
01057 
01058     return lh + ll;
01059 }
01060 
01061 VALUE
01062 rb_big2str0(VALUE x, int base, int trim)
01063 {
01064     int off;
01065     VALUE ss, xx;
01066     long n1, n2, len, hbase;
01067     char* ptr;
01068 
01069     if (FIXNUM_P(x)) {
01070         return rb_fix2str(x, base);
01071     }
01072     if (BIGZEROP(x)) {
01073         return rb_usascii_str_new2("0");
01074     }
01075 
01076     if (base < 2 || 36 < base)
01077         rb_raise(rb_eArgError, "invalid radix %d", base);
01078 
01079     n2 = big2str_find_n1(x, base);
01080     n1 = (n2 + 1) / 2;
01081     ss = rb_usascii_str_new(0, n2 + 1); /* plus one for sign */
01082     ptr = RSTRING_PTR(ss);
01083     ptr[0] = RBIGNUM_SIGN(x) ? '+' : '-';
01084 
01085     hbase = base*base;
01086 #if SIZEOF_BDIGITS > 2
01087     hbase *= hbase;
01088 #endif
01089     off = !(trim && RBIGNUM_SIGN(x)); /* erase plus sign if trim */
01090     xx = rb_big_clone(x);
01091     RBIGNUM_SET_SIGN(xx, 1);
01092     if (n1 <= KARATSUBA_DIGITS) {
01093         len = off + big2str_orig(xx, base, ptr + off, n2, hbase, trim);
01094     }
01095     else {
01096         len = off + big2str_karatsuba(xx, base, ptr + off, n1,
01097                                       n2, hbase, trim);
01098     }
01099     rb_big_resize(xx, 0);
01100 
01101     ptr[len] = '\0';
01102     rb_str_resize(ss, len);
01103 
01104     return ss;
01105 }
01106 
01107 VALUE
01108 rb_big2str(VALUE x, int base)
01109 {
01110     return rb_big2str0(x, base, 1);
01111 }
01112 
01113 /*
01114  *  call-seq:
01115  *     big.to_s(base=10)   ->  string
01116  *
01117  *  Returns a string containing the representation of <i>big</i> radix
01118  *  <i>base</i> (2 through 36).
01119  *
01120  *     12345654321.to_s         #=> "12345654321"
01121  *     12345654321.to_s(2)      #=> "1011011111110110111011110000110001"
01122  *     12345654321.to_s(8)      #=> "133766736061"
01123  *     12345654321.to_s(16)     #=> "2dfdbbc31"
01124  *     78546939656932.to_s(36)  #=> "rubyrules"
01125  */
01126 
01127 static VALUE
01128 rb_big_to_s(int argc, VALUE *argv, VALUE x)
01129 {
01130     int base;
01131 
01132     if (argc == 0) base = 10;
01133     else {
01134         VALUE b;
01135 
01136         rb_scan_args(argc, argv, "01", &b);
01137         base = NUM2INT(b);
01138     }
01139     return rb_big2str(x, base);
01140 }
01141 
01142 static VALUE
01143 big2ulong(VALUE x, const char *type, int check)
01144 {
01145     long len = RBIGNUM_LEN(x);
01146     BDIGIT_DBL num;
01147     BDIGIT *ds;
01148 
01149     if (len > DIGSPERLONG) {
01150         if (check)
01151             rb_raise(rb_eRangeError, "bignum too big to convert into `%s'", type);
01152         len = DIGSPERLONG;
01153     }
01154     ds = BDIGITS(x);
01155     num = 0;
01156     while (len--) {
01157         num = BIGUP(num);
01158         num += ds[len];
01159     }
01160     return (VALUE)num;
01161 }
01162 
01163 VALUE
01164 rb_big2ulong_pack(VALUE x)
01165 {
01166     VALUE num = big2ulong(x, "unsigned long", FALSE);
01167     if (!RBIGNUM_SIGN(x)) {
01168         return (VALUE)(-(SIGNED_VALUE)num);
01169     }
01170     return num;
01171 }
01172 
01173 VALUE
01174 rb_big2ulong(VALUE x)
01175 {
01176     VALUE num = big2ulong(x, "unsigned long", TRUE);
01177 
01178     if (!RBIGNUM_SIGN(x)) {
01179         if ((SIGNED_VALUE)num < 0) {
01180             rb_raise(rb_eRangeError, "bignum out of range of unsigned long");
01181         }
01182         return (VALUE)(-(SIGNED_VALUE)num);
01183     }
01184     return num;
01185 }
01186 
01187 SIGNED_VALUE
01188 rb_big2long(VALUE x)
01189 {
01190     VALUE num = big2ulong(x, "long", TRUE);
01191 
01192     if ((SIGNED_VALUE)num < 0 &&
01193         (RBIGNUM_SIGN(x) || (SIGNED_VALUE)num != LONG_MIN)) {
01194         rb_raise(rb_eRangeError, "bignum too big to convert into `long'");
01195     }
01196     if (!RBIGNUM_SIGN(x)) return -(SIGNED_VALUE)num;
01197     return num;
01198 }
01199 
01200 #if HAVE_LONG_LONG
01201 
01202 static unsigned LONG_LONG
01203 big2ull(VALUE x, const char *type)
01204 {
01205     long len = RBIGNUM_LEN(x);
01206     BDIGIT_DBL num;
01207     BDIGIT *ds;
01208 
01209     if (len > SIZEOF_LONG_LONG/SIZEOF_BDIGITS)
01210         rb_raise(rb_eRangeError, "bignum too big to convert into `%s'", type);
01211     ds = BDIGITS(x);
01212     num = 0;
01213     while (len--) {
01214         num = BIGUP(num);
01215         num += ds[len];
01216     }
01217     return num;
01218 }
01219 
01220 unsigned LONG_LONG
01221 rb_big2ull(VALUE x)
01222 {
01223     unsigned LONG_LONG num = big2ull(x, "unsigned long long");
01224 
01225     if (!RBIGNUM_SIGN(x))
01226         return (VALUE)(-(SIGNED_VALUE)num);
01227     return num;
01228 }
01229 
01230 LONG_LONG
01231 rb_big2ll(VALUE x)
01232 {
01233     unsigned LONG_LONG num = big2ull(x, "long long");
01234 
01235     if ((LONG_LONG)num < 0 && (RBIGNUM_SIGN(x)
01236                                || (LONG_LONG)num != LLONG_MIN)) {
01237         rb_raise(rb_eRangeError, "bignum too big to convert into `long long'");
01238     }
01239     if (!RBIGNUM_SIGN(x)) return -(LONG_LONG)num;
01240     return num;
01241 }
01242 
01243 #endif  /* HAVE_LONG_LONG */
01244 
01245 static VALUE
01246 dbl2big(double d)
01247 {
01248     long i = 0;
01249     BDIGIT c;
01250     BDIGIT *digits;
01251     VALUE z;
01252     double u = (d < 0)?-d:d;
01253 
01254     if (isinf(d)) {
01255         rb_raise(rb_eFloatDomainError, d < 0 ? "-Infinity" : "Infinity");
01256     }
01257     if (isnan(d)) {
01258         rb_raise(rb_eFloatDomainError, "NaN");
01259     }
01260 
01261     while (!POSFIXABLE(u) || 0 != (long)u) {
01262         u /= (double)(BIGRAD);
01263         i++;
01264     }
01265     z = bignew(i, d>=0);
01266     digits = BDIGITS(z);
01267     while (i--) {
01268         u *= BIGRAD;
01269         c = (BDIGIT)u;
01270         u -= c;
01271         digits[i] = c;
01272     }
01273 
01274     return z;
01275 }
01276 
01277 VALUE
01278 rb_dbl2big(double d)
01279 {
01280     return bignorm(dbl2big(d));
01281 }
01282 
01283 static int
01284 nlz(BDIGIT x)
01285 {
01286     BDIGIT y;
01287     int n = BITSPERDIG;
01288 #if BITSPERDIG > 64
01289     y = x >> 64; if (y) {n -= 64; x = y;}
01290 #endif
01291 #if BITSPERDIG > 32
01292     y = x >> 32; if (y) {n -= 32; x = y;}
01293 #endif
01294 #if BITSPERDIG > 16
01295     y = x >> 16; if (y) {n -= 16; x = y;}
01296 #endif
01297     y = x >>  8; if (y) {n -=  8; x = y;}
01298     y = x >>  4; if (y) {n -=  4; x = y;}
01299     y = x >>  2; if (y) {n -=  2; x = y;}
01300     y = x >>  1; if (y) {return n - 2;}
01301     return n - x;
01302 }
01303 
01304 static double
01305 big2dbl(VALUE x)
01306 {
01307     double d = 0.0;
01308     long i = (bigtrunc(x), RBIGNUM_LEN(x)), lo = 0, bits;
01309     BDIGIT *ds = BDIGITS(x), dl;
01310 
01311     if (i) {
01312         bits = i * BITSPERDIG - nlz(ds[i-1]);
01313         if (bits > DBL_MANT_DIG+DBL_MAX_EXP) {
01314             d = HUGE_VAL;
01315         }
01316         else {
01317             if (bits > DBL_MANT_DIG+1)
01318                 lo = (bits -= DBL_MANT_DIG+1) / BITSPERDIG;
01319             else
01320                 bits = 0;
01321             while (--i > lo) {
01322                 d = ds[i] + BIGRAD*d;
01323             }
01324             dl = ds[i];
01325             if (bits && (dl & (1UL << (bits %= BITSPERDIG)))) {
01326                 int carry = dl & ~(~(BDIGIT)0 << bits);
01327                 if (!carry) {
01328                     while (i-- > 0) {
01329                         if ((carry = ds[i]) != 0) break;
01330                     }
01331                 }
01332                 if (carry) {
01333                     dl &= (BDIGIT)~0 << bits;
01334                     dl += (BDIGIT)1 << bits;
01335                     if (!dl) d += 1;
01336                 }
01337             }
01338             d = dl + BIGRAD*d;
01339             if (lo) {
01340                 if (lo > INT_MAX / BITSPERDIG)
01341                     d = HUGE_VAL;
01342                 else if (lo < INT_MIN / BITSPERDIG)
01343                     d = 0.0;
01344                 else
01345                     d = ldexp(d, (int)(lo * BITSPERDIG));
01346             }
01347         }
01348     }
01349     if (!RBIGNUM_SIGN(x)) d = -d;
01350     return d;
01351 }
01352 
01353 double
01354 rb_big2dbl(VALUE x)
01355 {
01356     double d = big2dbl(x);
01357 
01358     if (isinf(d)) {
01359         rb_warning("Bignum out of Float range");
01360         if (d < 0.0)
01361             d = -HUGE_VAL;
01362         else
01363             d = HUGE_VAL;
01364     }
01365     return d;
01366 }
01367 
01368 /*
01369  *  call-seq:
01370  *     big.to_f -> float
01371  *
01372  *  Converts <i>big</i> to a <code>Float</code>. If <i>big</i> doesn't
01373  *  fit in a <code>Float</code>, the result is infinity.
01374  *
01375  */
01376 
01377 static VALUE
01378 rb_big_to_f(VALUE x)
01379 {
01380     return DBL2NUM(rb_big2dbl(x));
01381 }
01382 
01383 /*
01384  *  call-seq:
01385  *     big <=> numeric   -> -1, 0, +1 or nil
01386  *
01387  *  Comparison---Returns -1, 0, or +1 depending on whether <i>big</i> is
01388  *  less than, equal to, or greater than <i>numeric</i>. This is the
01389  *  basis for the tests in <code>Comparable</code>.
01390  *
01391  */
01392 
01393 VALUE
01394 rb_big_cmp(VALUE x, VALUE y)
01395 {
01396     long xlen = RBIGNUM_LEN(x);
01397     BDIGIT *xds, *yds;
01398 
01399     switch (TYPE(y)) {
01400       case T_FIXNUM:
01401         y = rb_int2big(FIX2LONG(y));
01402         break;
01403 
01404       case T_BIGNUM:
01405         break;
01406 
01407       case T_FLOAT:
01408         {
01409             double a = RFLOAT_VALUE(y);
01410 
01411             if (isinf(a)) {
01412                 if (a > 0.0) return INT2FIX(-1);
01413                 else return INT2FIX(1);
01414             }
01415             return rb_dbl_cmp(rb_big2dbl(x), a);
01416         }
01417 
01418       default:
01419         return rb_num_coerce_cmp(x, y, rb_intern("<=>"));
01420     }
01421 
01422     if (RBIGNUM_SIGN(x) > RBIGNUM_SIGN(y)) return INT2FIX(1);
01423     if (RBIGNUM_SIGN(x) < RBIGNUM_SIGN(y)) return INT2FIX(-1);
01424     if (xlen < RBIGNUM_LEN(y))
01425         return (RBIGNUM_SIGN(x)) ? INT2FIX(-1) : INT2FIX(1);
01426     if (xlen > RBIGNUM_LEN(y))
01427         return (RBIGNUM_SIGN(x)) ? INT2FIX(1) : INT2FIX(-1);
01428 
01429     xds = BDIGITS(x);
01430     yds = BDIGITS(y);
01431 
01432     while(xlen-- && (xds[xlen]==yds[xlen]));
01433     if (-1 == xlen) return INT2FIX(0);
01434     return (xds[xlen] > yds[xlen]) ?
01435         (RBIGNUM_SIGN(x) ? INT2FIX(1) : INT2FIX(-1)) :
01436             (RBIGNUM_SIGN(x) ? INT2FIX(-1) : INT2FIX(1));
01437 }
01438 
01439 static VALUE
01440 big_op(VALUE x, VALUE y, int op)
01441 {
01442     VALUE rel;
01443     int n;
01444 
01445     switch (TYPE(y)) {
01446       case T_FIXNUM:
01447       case T_BIGNUM:
01448         rel = rb_big_cmp(x, y);
01449         break;
01450 
01451       case T_FLOAT:
01452         {
01453             double a = RFLOAT_VALUE(y);
01454 
01455             if (isinf(a)) {
01456                 if (a > 0.0) rel = INT2FIX(-1);
01457                 else rel = INT2FIX(1);
01458                 break;
01459             }
01460             rel = rb_dbl_cmp(rb_big2dbl(x), a);
01461             break;
01462         }
01463 
01464       default:
01465         {
01466             ID id = 0;
01467             switch (op) {
01468                 case 0: id = '>'; break;
01469                 case 1: id = rb_intern(">="); break;
01470                 case 2: id = '<'; break;
01471                 case 3: id = rb_intern("<="); break;
01472             }
01473             return rb_num_coerce_relop(x, y, id);
01474         }
01475     }
01476 
01477     if (NIL_P(rel)) return Qfalse;
01478     n = FIX2INT(rel);
01479 
01480     switch (op) {
01481         case 0: return n >  0 ? Qtrue : Qfalse;
01482         case 1: return n >= 0 ? Qtrue : Qfalse;
01483         case 2: return n <  0 ? Qtrue : Qfalse;
01484         case 3: return n <= 0 ? Qtrue : Qfalse;
01485     }
01486     return Qundef;
01487 }
01488 
01489 /*
01490  * call-seq:
01491  *   big > real  ->  true or false
01492  *
01493  * Returns <code>true</code> if the value of <code>big</code> is
01494  * greater than that of <code>real</code>.
01495  */
01496 
01497 static VALUE
01498 big_gt(VALUE x, VALUE y)
01499 {
01500     return big_op(x, y, 0);
01501 }
01502 
01503 /*
01504  * call-seq:
01505  *   big >= real  ->  true or false
01506  *
01507  * Returns <code>true</code> if the value of <code>big</code> is
01508  * greater than or equal to that of <code>real</code>.
01509  */
01510 
01511 static VALUE
01512 big_ge(VALUE x, VALUE y)
01513 {
01514     return big_op(x, y, 1);
01515 }
01516 
01517 /*
01518  * call-seq:
01519  *   big < real  ->  true or false
01520  *
01521  * Returns <code>true</code> if the value of <code>big</code> is
01522  * less than that of <code>real</code>.
01523  */
01524 
01525 static VALUE
01526 big_lt(VALUE x, VALUE y)
01527 {
01528     return big_op(x, y, 2);
01529 }
01530 
01531 /*
01532  * call-seq:
01533  *   big <= real  ->  true or false
01534  *
01535  * Returns <code>true</code> if the value of <code>big</code> is
01536  * less than or equal to that of <code>real</code>.
01537  */
01538 
01539 static VALUE
01540 big_le(VALUE x, VALUE y)
01541 {
01542     return big_op(x, y, 3);
01543 }
01544 
01545 /*
01546  *  call-seq:
01547  *     big == obj  -> true or false
01548  *
01549  *  Returns <code>true</code> only if <i>obj</i> has the same value
01550  *  as <i>big</i>. Contrast this with <code>Bignum#eql?</code>, which
01551  *  requires <i>obj</i> to be a <code>Bignum</code>.
01552  *
01553  *     68719476736 == 68719476736.0   #=> true
01554  */
01555 
01556 VALUE
01557 rb_big_eq(VALUE x, VALUE y)
01558 {
01559     switch (TYPE(y)) {
01560       case T_FIXNUM:
01561         y = rb_int2big(FIX2LONG(y));
01562         break;
01563       case T_BIGNUM:
01564         break;
01565       case T_FLOAT:
01566         {
01567             volatile double a, b;
01568 
01569             a = RFLOAT_VALUE(y);
01570             if (isnan(a)) return Qfalse;
01571             b = rb_big2dbl(x);
01572             return (a == b)?Qtrue:Qfalse;
01573         }
01574       default:
01575         return rb_equal(y, x);
01576     }
01577     if (RBIGNUM_SIGN(x) != RBIGNUM_SIGN(y)) return Qfalse;
01578     if (RBIGNUM_LEN(x) != RBIGNUM_LEN(y)) return Qfalse;
01579     if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM_LEN(y)) != 0) return Qfalse;
01580     return Qtrue;
01581 }
01582 
01583 /*
01584  *  call-seq:
01585  *     big.eql?(obj)   -> true or false
01586  *
01587  *  Returns <code>true</code> only if <i>obj</i> is a
01588  *  <code>Bignum</code> with the same value as <i>big</i>. Contrast this
01589  *  with <code>Bignum#==</code>, which performs type conversions.
01590  *
01591  *     68719476736.eql?(68719476736.0)   #=> false
01592  */
01593 
01594 static VALUE
01595 rb_big_eql(VALUE x, VALUE y)
01596 {
01597     if (TYPE(y) != T_BIGNUM) return Qfalse;
01598     if (RBIGNUM_SIGN(x) != RBIGNUM_SIGN(y)) return Qfalse;
01599     if (RBIGNUM_LEN(x) != RBIGNUM_LEN(y)) return Qfalse;
01600     if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM_LEN(y)) != 0) return Qfalse;
01601     return Qtrue;
01602 }
01603 
01604 /*
01605  * call-seq:
01606  *    -big   ->  integer
01607  *
01608  * Unary minus (returns an integer whose value is 0-big)
01609  */
01610 
01611 static VALUE
01612 rb_big_uminus(VALUE x)
01613 {
01614     VALUE z = rb_big_clone(x);
01615 
01616     RBIGNUM_SET_SIGN(z, !RBIGNUM_SIGN(x));
01617 
01618     return bignorm(z);
01619 }
01620 
01621 /*
01622  * call-seq:
01623  *     ~big  ->  integer
01624  *
01625  * Inverts the bits in big. As Bignums are conceptually infinite
01626  * length, the result acts as if it had an infinite number of one
01627  * bits to the left. In hex representations, this is displayed
01628  * as two periods to the left of the digits.
01629  *
01630  *   sprintf("%X", ~0x1122334455)    #=> "..FEEDDCCBBAA"
01631  */
01632 
01633 static VALUE
01634 rb_big_neg(VALUE x)
01635 {
01636     VALUE z = rb_big_clone(x);
01637     BDIGIT *ds;
01638     long i;
01639 
01640     if (!RBIGNUM_SIGN(x)) get2comp(z);
01641     ds = BDIGITS(z);
01642     i = RBIGNUM_LEN(x);
01643     if (!i) return INT2FIX(~(SIGNED_VALUE)0);
01644     while (i--) {
01645         ds[i] = ~ds[i];
01646     }
01647     RBIGNUM_SET_SIGN(z, !RBIGNUM_SIGN(z));
01648     if (RBIGNUM_SIGN(x)) get2comp(z);
01649 
01650     return bignorm(z);
01651 }
01652 
01653 static void
01654 bigsub_core(BDIGIT *xds, long xn, BDIGIT *yds, long yn, BDIGIT *zds, long zn)
01655 {
01656     BDIGIT_DBL_SIGNED num;
01657     long i;
01658 
01659     for (i = 0, num = 0; i < yn; i++) {
01660         num += (BDIGIT_DBL_SIGNED)xds[i] - yds[i];
01661         zds[i] = BIGLO(num);
01662         num = BIGDN(num);
01663     }
01664     while (num && i < xn) {
01665         num += xds[i];
01666         zds[i++] = BIGLO(num);
01667         num = BIGDN(num);
01668     }
01669     while (i < xn) {
01670         zds[i] = xds[i];
01671         i++;
01672     }
01673     assert(i <= zn);
01674     while (i < zn) {
01675         zds[i++] = 0;
01676     }
01677 }
01678 
01679 static VALUE
01680 bigsub(VALUE x, VALUE y)
01681 {
01682     VALUE z = 0;
01683     long i = RBIGNUM_LEN(x);
01684     BDIGIT *xds, *yds;
01685 
01686     /* if x is larger than y, swap */
01687     if (RBIGNUM_LEN(x) < RBIGNUM_LEN(y)) {
01688         z = x; x = y; y = z;    /* swap x y */
01689     }
01690     else if (RBIGNUM_LEN(x) == RBIGNUM_LEN(y)) {
01691         xds = BDIGITS(x);
01692         yds = BDIGITS(y);
01693         while (i > 0) {
01694             i--;
01695             if (xds[i] > yds[i]) {
01696                 break;
01697             }
01698             if (xds[i] < yds[i]) {
01699                 z = x; x = y; y = z;    /* swap x y */
01700                 break;
01701             }
01702         }
01703     }
01704 
01705     z = bignew(RBIGNUM_LEN(x), z==0);
01706     bigsub_core(BDIGITS(x), RBIGNUM_LEN(x),
01707                 BDIGITS(y), RBIGNUM_LEN(y),
01708                 BDIGITS(z), RBIGNUM_LEN(z));
01709 
01710     return z;
01711 }
01712 
01713 static VALUE bigadd_int(VALUE x, long y);
01714 
01715 static VALUE
01716 bigsub_int(VALUE x, long y0)
01717 {
01718     VALUE z;
01719     BDIGIT *xds, *zds;
01720     long xn;
01721     BDIGIT_DBL_SIGNED num;
01722     long i, y;
01723 
01724     y = y0;
01725     xds = BDIGITS(x);
01726     xn = RBIGNUM_LEN(x);
01727 
01728     z = bignew(xn, RBIGNUM_SIGN(x));
01729     zds = BDIGITS(z);
01730 
01731 #if SIZEOF_BDIGITS == SIZEOF_LONG
01732     num = (BDIGIT_DBL_SIGNED)xds[0] - y;
01733     if (xn == 1 && num < 0) {
01734         RBIGNUM_SET_SIGN(z, !RBIGNUM_SIGN(x));
01735         zds[0] = (BDIGIT)-num;
01736         return bignorm(z);
01737     }
01738     zds[0] = BIGLO(num);
01739     num = BIGDN(num);
01740     i = 1;
01741 #else
01742     num = 0;
01743     for (i=0; i<(int)(sizeof(y)/sizeof(BDIGIT)); i++) {
01744         num += (BDIGIT_DBL_SIGNED)xds[i] - BIGLO(y);
01745         zds[i] = BIGLO(num);
01746         num = BIGDN(num);
01747         y = BIGDN(y);
01748     }
01749 #endif
01750     while (num && i < xn) {
01751         num += xds[i];
01752         zds[i++] = BIGLO(num);
01753         num = BIGDN(num);
01754     }
01755     while (i < xn) {
01756         zds[i] = xds[i];
01757         i++;
01758     }
01759     if (num < 0) {
01760         z = bigsub(x, rb_int2big(y0));
01761     }
01762     return bignorm(z);
01763 }
01764 
01765 static VALUE
01766 bigadd_int(VALUE x, long y)
01767 {
01768     VALUE z;
01769     BDIGIT *xds, *zds;
01770     long xn, zn;
01771     BDIGIT_DBL num;
01772     long i;
01773 
01774     xds = BDIGITS(x);
01775     xn = RBIGNUM_LEN(x);
01776 
01777     if (xn < 2) {
01778         zn = 3;
01779     }
01780     else {
01781         zn = xn + 1;
01782     }
01783     z = bignew(zn, RBIGNUM_SIGN(x));
01784     zds = BDIGITS(z);
01785 
01786 #if SIZEOF_BDIGITS == SIZEOF_LONG
01787     num = (BDIGIT_DBL)xds[0] + y;
01788     zds[0] = BIGLO(num);
01789     num = BIGDN(num);
01790     i = 1;
01791 #else
01792     num = 0;
01793     for (i=0; i<(int)(sizeof(y)/sizeof(BDIGIT)); i++) {
01794         num += (BDIGIT_DBL)xds[i] + BIGLO(y);
01795         zds[i] = BIGLO(num);
01796         num = BIGDN(num);
01797         y = BIGDN(y);
01798     }
01799 #endif
01800     while (num && i < xn) {
01801         num += xds[i];
01802         zds[i++] = BIGLO(num);
01803         num = BIGDN(num);
01804     }
01805     if (num) zds[i++] = (BDIGIT)num;
01806     else while (i < xn) {
01807         zds[i] = xds[i];
01808         i++;
01809     }
01810     assert(i <= zn);
01811     while (i < zn) {
01812         zds[i++] = 0;
01813     }
01814     return bignorm(z);
01815 }
01816 
01817 static void
01818 bigadd_core(BDIGIT *xds, long xn, BDIGIT *yds, long yn, BDIGIT *zds, long zn)
01819 {
01820     BDIGIT_DBL num = 0;
01821     long i;
01822 
01823     if (xn > yn) {
01824         BDIGIT *tds;
01825         tds = xds; xds = yds; yds = tds;
01826         i = xn; xn = yn; yn = i;
01827     }
01828 
01829     i = 0;
01830     while (i < xn) {
01831         num += (BDIGIT_DBL)xds[i] + yds[i];
01832         zds[i++] = BIGLO(num);
01833         num = BIGDN(num);
01834     }
01835     while (num && i < yn) {
01836         num += yds[i];
01837         zds[i++] = BIGLO(num);
01838         num = BIGDN(num);
01839     }
01840     while (i < yn) {
01841         zds[i] = yds[i];
01842         i++;
01843     }
01844     if (num) zds[i++] = (BDIGIT)num;
01845     assert(i <= zn);
01846     while (i < zn) {
01847         zds[i++] = 0;
01848     }
01849 }
01850 
01851 static VALUE
01852 bigadd(VALUE x, VALUE y, int sign)
01853 {
01854     VALUE z;
01855     long len;
01856 
01857     sign = (sign == RBIGNUM_SIGN(y));
01858     if (RBIGNUM_SIGN(x) != sign) {
01859         if (sign) return bigsub(y, x);
01860         return bigsub(x, y);
01861     }
01862 
01863     if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
01864         len = RBIGNUM_LEN(x) + 1;
01865     }
01866     else {
01867         len = RBIGNUM_LEN(y) + 1;
01868     }
01869     z = bignew(len, sign);
01870 
01871     bigadd_core(BDIGITS(x), RBIGNUM_LEN(x),
01872                 BDIGITS(y), RBIGNUM_LEN(y),
01873                 BDIGITS(z), RBIGNUM_LEN(z));
01874 
01875     return z;
01876 }
01877 
01878 /*
01879  *  call-seq:
01880  *     big + other  -> Numeric
01881  *
01882  *  Adds big and other, returning the result.
01883  */
01884 
01885 VALUE
01886 rb_big_plus(VALUE x, VALUE y)
01887 {
01888     long n;
01889 
01890     switch (TYPE(y)) {
01891       case T_FIXNUM:
01892         n = FIX2LONG(y);
01893         if ((n > 0) != RBIGNUM_SIGN(x)) {
01894             if (n < 0) {
01895                 n = -n;
01896             }
01897             return bigsub_int(x, n);
01898         }
01899         if (n < 0) {
01900             n = -n;
01901         }
01902         return bigadd_int(x, n);
01903 
01904       case T_BIGNUM:
01905         return bignorm(bigadd(x, y, 1));
01906 
01907       case T_FLOAT:
01908         return DBL2NUM(rb_big2dbl(x) + RFLOAT_VALUE(y));
01909 
01910       default:
01911         return rb_num_coerce_bin(x, y, '+');
01912     }
01913 }
01914 
01915 /*
01916  *  call-seq:
01917  *     big - other  -> Numeric
01918  *
01919  *  Subtracts other from big, returning the result.
01920  */
01921 
01922 VALUE
01923 rb_big_minus(VALUE x, VALUE y)
01924 {
01925     long n;
01926 
01927     switch (TYPE(y)) {
01928       case T_FIXNUM:
01929         n = FIX2LONG(y);
01930         if ((n > 0) != RBIGNUM_SIGN(x)) {
01931             if (n < 0) {
01932                 n = -n;
01933             }
01934             return bigadd_int(x, n);
01935         }
01936         if (n < 0) {
01937             n = -n;
01938         }
01939         return bigsub_int(x, n);
01940 
01941       case T_BIGNUM:
01942         return bignorm(bigadd(x, y, 0));
01943 
01944       case T_FLOAT:
01945         return DBL2NUM(rb_big2dbl(x) - RFLOAT_VALUE(y));
01946 
01947       default:
01948         return rb_num_coerce_bin(x, y, '-');
01949     }
01950 }
01951 
01952 static long
01953 big_real_len(VALUE x)
01954 {
01955     long i = RBIGNUM_LEN(x);
01956     BDIGIT *xds = BDIGITS(x);
01957     while (--i && !xds[i]);
01958     return i + 1;
01959 }
01960 
01961 static VALUE
01962 bigmul1_single(VALUE x, VALUE y)
01963 {
01964     BDIGIT_DBL n;
01965     VALUE z = bignew(2, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
01966     BDIGIT *xds, *yds, *zds;
01967 
01968     xds = BDIGITS(x);
01969     yds = BDIGITS(y);
01970     zds = BDIGITS(z);
01971 
01972     n = (BDIGIT_DBL)xds[0] * yds[0];
01973     zds[0] = BIGLO(n);
01974     zds[1] = (BDIGIT)BIGDN(n);
01975 
01976     return z;
01977 }
01978 
01979 static VALUE
01980 bigmul1_normal(VALUE x, VALUE y)
01981 {
01982     long xl = RBIGNUM_LEN(x), yl = RBIGNUM_LEN(y), i, j = xl + yl + 1;
01983     BDIGIT_DBL n = 0;
01984     VALUE z = bignew(j, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
01985     BDIGIT *xds, *yds, *zds;
01986 
01987     xds = BDIGITS(x);
01988     yds = BDIGITS(y);
01989     zds = BDIGITS(z);
01990     while (j--) zds[j] = 0;
01991     for (i = 0; i < xl; i++) {
01992         BDIGIT_DBL dd;
01993         dd = xds[i];
01994         if (dd == 0) continue;
01995         n = 0;
01996         for (j = 0; j < yl; j++) {
01997             BDIGIT_DBL ee = n + (BDIGIT_DBL)dd * yds[j];
01998             n = zds[i + j] + ee;
01999             if (ee) zds[i + j] = BIGLO(n);
02000             n = BIGDN(n);
02001         }
02002         if (n) {
02003             zds[i + j] = (BDIGIT)n;
02004         }
02005     }
02006     rb_thread_check_ints();
02007     return z;
02008 }
02009 
02010 static VALUE bigmul0(VALUE x, VALUE y);
02011 
02012 /* balancing multiplication by slicing larger argument */
02013 static VALUE
02014 bigmul1_balance(VALUE x, VALUE y)
02015 {
02016     VALUE z, t1, t2;
02017     long i, xn, yn, r, n;
02018     BDIGIT *yds, *zds, *t1ds;
02019 
02020     xn = RBIGNUM_LEN(x);
02021     yn = RBIGNUM_LEN(y);
02022     assert(2 * xn <= yn);
02023 
02024     z = bignew(xn + yn, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
02025     t1 = bignew(xn, 1);
02026 
02027     yds = BDIGITS(y);
02028     zds = BDIGITS(z);
02029     t1ds = BDIGITS(t1);
02030 
02031     for (i = 0; i < xn + yn; i++) zds[i] = 0;
02032 
02033     n = 0;
02034     while (yn > 0) {
02035         r = xn > yn ? yn : xn;
02036         MEMCPY(t1ds, yds + n, BDIGIT, r);
02037         RBIGNUM_SET_LEN(t1, r);
02038         t2 = bigmul0(x, t1);
02039         bigadd_core(zds + n, RBIGNUM_LEN(z) - n,
02040                     BDIGITS(t2), big_real_len(t2),
02041                     zds + n, RBIGNUM_LEN(z) - n);
02042         yn -= r;
02043         n += r;
02044     }
02045 
02046     return z;
02047 }
02048 
02049 /* split a bignum into high and low bignums */
02050 static void
02051 big_split(VALUE v, long n, volatile VALUE *ph, volatile VALUE *pl)
02052 {
02053     long hn = 0, ln = RBIGNUM_LEN(v);
02054     VALUE h, l;
02055     BDIGIT *vds = BDIGITS(v);
02056 
02057     if (ln > n) {
02058         hn = ln - n;
02059         ln = n;
02060     }
02061 
02062     while (--hn && !vds[hn + ln]);
02063     h = bignew(hn += 2, 1);
02064     MEMCPY(BDIGITS(h), vds + ln, BDIGIT, hn - 1);
02065     BDIGITS(h)[hn - 1] = 0; /* margin for carry */
02066 
02067     while (--ln && !vds[ln]);
02068     l = bignew(ln += 2, 1);
02069     MEMCPY(BDIGITS(l), vds, BDIGIT, ln - 1);
02070     BDIGITS(l)[ln - 1] = 0; /* margin for carry */
02071 
02072     *pl = l;
02073     *ph = h;
02074 }
02075 
02076 /* multiplication by karatsuba method */
02077 static VALUE
02078 bigmul1_karatsuba(VALUE x, VALUE y)
02079 {
02080     long i, n, xn, yn, t1n, t2n;
02081     VALUE xh, xl, yh, yl, z, t1, t2, t3;
02082     BDIGIT *zds;
02083 
02084     xn = RBIGNUM_LEN(x);
02085     yn = RBIGNUM_LEN(y);
02086     n = yn / 2;
02087     big_split(x, n, &xh, &xl);
02088     if (x == y) {
02089         yh = xh; yl = xl;
02090     }
02091     else big_split(y, n, &yh, &yl);
02092 
02093     /* x = xh * b + xl
02094      * y = yh * b + yl
02095      *
02096      * Karatsuba method:
02097      *   x * y = z2 * b^2 + z1 * b + z0
02098      *   where
02099      *     z2 = xh * yh
02100      *     z0 = xl * yl
02101      *     z1 = (xh + xl) * (yh + yl) - z2 - z0
02102      *
02103      *  ref: http://en.wikipedia.org/wiki/Karatsuba_algorithm
02104      */
02105 
02106     /* allocate a result bignum */
02107     z = bignew(xn + yn, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
02108     zds = BDIGITS(z);
02109 
02110     /* t1 <- xh * yh */
02111     t1 = bigmul0(xh, yh);
02112     t1n = big_real_len(t1);
02113 
02114     /* copy t1 into high bytes of the result (z2) */
02115     MEMCPY(zds + 2 * n, BDIGITS(t1), BDIGIT, t1n);
02116     for (i = 2 * n + t1n; i < xn + yn; i++) zds[i] = 0;
02117 
02118     if (!BIGZEROP(xl) && !BIGZEROP(yl)) {
02119         /* t2 <- xl * yl */
02120         t2 = bigmul0(xl, yl);
02121         t2n = big_real_len(t2);
02122 
02123         /* copy t2 into low bytes of the result (z0) */
02124         MEMCPY(zds, BDIGITS(t2), BDIGIT, t2n);
02125         for (i = t2n; i < 2 * n; i++) zds[i] = 0;
02126     }
02127     else {
02128         t2 = Qundef;
02129         t2n = 0;
02130 
02131         /* copy 0 into low bytes of the result (z0) */
02132         for (i = 0; i < 2 * n; i++) zds[i] = 0;
02133     }
02134 
02135     /* xh <- xh + xl */
02136     if (RBIGNUM_LEN(xl) > RBIGNUM_LEN(xh)) {
02137         t3 = xl; xl = xh; xh = t3;
02138     }
02139     /* xh has a margin for carry */
02140     bigadd_core(BDIGITS(xh), RBIGNUM_LEN(xh),
02141                 BDIGITS(xl), RBIGNUM_LEN(xl),
02142                 BDIGITS(xh), RBIGNUM_LEN(xh));
02143 
02144     /* yh <- yh + yl */
02145     if (x != y) {
02146         if (RBIGNUM_LEN(yl) > RBIGNUM_LEN(yh)) {
02147             t3 = yl; yl = yh; yh = t3;
02148         }
02149         /* yh has a margin for carry */
02150         bigadd_core(BDIGITS(yh), RBIGNUM_LEN(yh),
02151                     BDIGITS(yl), RBIGNUM_LEN(yl),
02152                     BDIGITS(yh), RBIGNUM_LEN(yh));
02153     }
02154     else yh = xh;
02155 
02156     /* t3 <- xh * yh */
02157     t3 = bigmul0(xh, yh);
02158 
02159     i = xn + yn - n;
02160     /* subtract t1 from t3 */
02161     bigsub_core(BDIGITS(t3), big_real_len(t3), BDIGITS(t1), t1n, BDIGITS(t3), big_real_len(t3));
02162 
02163     /* subtract t2 from t3; t3 is now the middle term of the product */
02164     if (t2 != Qundef) bigsub_core(BDIGITS(t3), big_real_len(t3), BDIGITS(t2), t2n, BDIGITS(t3), big_real_len(t3));
02165 
02166     /* add t3 to middle bytes of the result (z1) */
02167     bigadd_core(zds + n, i, BDIGITS(t3), big_real_len(t3), zds + n, i);
02168 
02169     return z;
02170 }
02171 
02172 /* efficient squaring (2 times faster than normal multiplication)
02173  * ref: Handbook of Applied Cryptography, Algorithm 14.16
02174  *      http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
02175  */
02176 static VALUE
02177 bigsqr_fast(VALUE x)
02178 {
02179     long len = RBIGNUM_LEN(x), i, j;
02180     VALUE z = bignew(2 * len + 1, 1);
02181     BDIGIT *xds = BDIGITS(x), *zds = BDIGITS(z);
02182     BDIGIT_DBL c, v, w;
02183 
02184     for (i = 2 * len + 1; i--; ) zds[i] = 0;
02185     for (i = 0; i < len; i++) {
02186         v = (BDIGIT_DBL)xds[i];
02187         if (!v) continue;
02188         c = (BDIGIT_DBL)zds[i + i] + v * v;
02189         zds[i + i] = BIGLO(c);
02190         c = BIGDN(c);
02191         v *= 2;
02192         for (j = i + 1; j < len; j++) {
02193             w = (BDIGIT_DBL)xds[j];
02194             c += (BDIGIT_DBL)zds[i + j] + BIGLO(v) * w;
02195             zds[i + j] = BIGLO(c);
02196             c = BIGDN(c);
02197             if (BIGDN(v)) c += w;
02198         }
02199         if (c) {
02200             c += (BDIGIT_DBL)zds[i + len];
02201             zds[i + len] = BIGLO(c);
02202             c = BIGDN(c);
02203         }
02204         if (c) zds[i + len + 1] += (BDIGIT)c;
02205     }
02206     return z;
02207 }
02208 
02209 #define KARATSUBA_MUL_DIGITS 70
02210 
02211 
02212 /* determine whether a bignum is sparse or not by random sampling */
02213 static inline VALUE
02214 big_sparse_p(VALUE x)
02215 {
02216     long c = 0, n = RBIGNUM_LEN(x);
02217     unsigned long rb_rand_internal(unsigned long i);
02218 
02219     if (          BDIGITS(x)[rb_rand_internal(n / 2) + n / 4]) c++;
02220     if (c <= 1 && BDIGITS(x)[rb_rand_internal(n / 2) + n / 4]) c++;
02221     if (c <= 1 && BDIGITS(x)[rb_rand_internal(n / 2) + n / 4]) c++;
02222 
02223     return (c <= 1) ? Qtrue : Qfalse;
02224 }
02225 
02226 #if 0
02227 static void
02228 dump_bignum(VALUE x)
02229 {
02230     long i;
02231     printf("0x0");
02232     for (i = RBIGNUM_LEN(x); i--; ) {
02233         printf("_%08x", BDIGITS(x)[i]);
02234     }
02235     puts("");
02236 }
02237 #endif
02238 
02239 static VALUE
02240 bigmul0(VALUE x, VALUE y)
02241 {
02242     long xn, yn;
02243 
02244     xn = RBIGNUM_LEN(x);
02245     yn = RBIGNUM_LEN(y);
02246 
02247     /* make sure that y is longer than x */
02248     if (xn > yn) {
02249         VALUE t;
02250         long tn;
02251         t = x; x = y; y = t;
02252         tn = xn; xn = yn; yn = tn;
02253     }
02254     assert(xn <= yn);
02255 
02256     /* normal multiplication when x is small */
02257     if (xn < KARATSUBA_MUL_DIGITS) {
02258       normal:
02259         if (x == y) return bigsqr_fast(x);
02260         if (xn == 1 && yn == 1) return bigmul1_single(x, y);
02261         return bigmul1_normal(x, y);
02262     }
02263 
02264     /* normal multiplication when x or y is a sparse bignum */
02265     if (big_sparse_p(x)) goto normal;
02266     if (big_sparse_p(y)) return bigmul1_normal(y, x);
02267 
02268     /* balance multiplication by slicing y when x is much smaller than y */
02269     if (2 * xn <= yn) return bigmul1_balance(x, y);
02270 
02271     /* multiplication by karatsuba method */
02272     return bigmul1_karatsuba(x, y);
02273 }
02274 
02275 /*
02276  *  call-seq:
02277  *     big * other  -> Numeric
02278  *
02279  *  Multiplies big and other, returning the result.
02280  */
02281 
02282 VALUE
02283 rb_big_mul(VALUE x, VALUE y)
02284 {
02285     switch (TYPE(y)) {
02286       case T_FIXNUM:
02287         y = rb_int2big(FIX2LONG(y));
02288         break;
02289 
02290       case T_BIGNUM:
02291         break;
02292 
02293       case T_FLOAT:
02294         return DBL2NUM(rb_big2dbl(x) * RFLOAT_VALUE(y));
02295 
02296       default:
02297         return rb_num_coerce_bin(x, y, '*');
02298     }
02299 
02300     return bignorm(bigmul0(x, y));
02301 }
02302 
02303 struct big_div_struct {
02304     long nx, ny;
02305     BDIGIT *yds, *zds;
02306     VALUE stop;
02307 };
02308 
02309 static VALUE
02310 bigdivrem1(void *ptr)
02311 {
02312     struct big_div_struct *bds = (struct big_div_struct*)ptr;
02313     long nx = bds->nx, ny = bds->ny;
02314     long i, j, nyzero;
02315     BDIGIT *yds = bds->yds, *zds = bds->zds;
02316     BDIGIT_DBL t2;
02317     BDIGIT_DBL_SIGNED num;
02318     BDIGIT q;
02319 
02320     j = nx==ny?nx+1:nx;
02321     for (nyzero = 0; !yds[nyzero]; nyzero++);
02322     do {
02323         if (bds->stop) return Qnil;
02324         if (zds[j] ==  yds[ny-1]) q = (BDIGIT)BIGRAD-1;
02325         else q = (BDIGIT)((BIGUP(zds[j]) + zds[j-1])/yds[ny-1]);
02326         if (q) {
02327            i = nyzero; num = 0; t2 = 0;
02328             do {                        /* multiply and subtract */
02329                 BDIGIT_DBL ee;
02330                 t2 += (BDIGIT_DBL)yds[i] * q;
02331                 ee = num - BIGLO(t2);
02332                 num = (BDIGIT_DBL)zds[j - ny + i] + ee;
02333                 if (ee) zds[j - ny + i] = BIGLO(num);
02334                 num = BIGDN(num);
02335                 t2 = BIGDN(t2);
02336             } while (++i < ny);
02337             num += zds[j - ny + i] - t2;/* borrow from high digit; don't update */
02338             while (num) {               /* "add back" required */
02339                 i = 0; num = 0; q--;
02340                 do {
02341                     BDIGIT_DBL ee = num + yds[i];
02342                     num = (BDIGIT_DBL)zds[j - ny + i] + ee;
02343                     if (ee) zds[j - ny + i] = BIGLO(num);
02344                     num = BIGDN(num);
02345                 } while (++i < ny);
02346                 num--;
02347             }
02348         }
02349         zds[j] = q;
02350     } while (--j >= ny);
02351     return Qnil;
02352 }
02353 
02354 static void
02355 rb_big_stop(void *ptr)
02356 {
02357     VALUE *stop = (VALUE*)ptr;
02358     *stop = Qtrue;
02359 }
02360 
02361 static VALUE
02362 bigdivrem(VALUE x, VALUE y, volatile VALUE *divp, volatile VALUE *modp)
02363 {
02364     struct big_div_struct bds;
02365     long nx = RBIGNUM_LEN(x), ny = RBIGNUM_LEN(y);
02366     long i, j;
02367     VALUE z, yy, zz;
02368     BDIGIT *xds, *yds, *zds, *tds;
02369     BDIGIT_DBL t2;
02370     BDIGIT dd, q;
02371 
02372     if (BIGZEROP(y)) rb_num_zerodiv();
02373     xds = BDIGITS(x);
02374     yds = BDIGITS(y);
02375     if (nx < ny || (nx == ny && xds[nx - 1] < yds[ny - 1])) {
02376         if (divp) *divp = rb_int2big(0);
02377         if (modp) *modp = x;
02378         return Qnil;
02379     }
02380     if (ny == 1) {
02381         dd = yds[0];
02382         z = rb_big_clone(x);
02383         zds = BDIGITS(z);
02384         t2 = 0; i = nx;
02385         while (i--) {
02386             t2 = BIGUP(t2) + zds[i];
02387             zds[i] = (BDIGIT)(t2 / dd);
02388             t2 %= dd;
02389         }
02390         RBIGNUM_SET_SIGN(z, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
02391         if (modp) {
02392             *modp = rb_uint2big((VALUE)t2);
02393             RBIGNUM_SET_SIGN(*modp, RBIGNUM_SIGN(x));
02394         }
02395         if (divp) *divp = z;
02396         return Qnil;
02397     }
02398     z = bignew(nx==ny?nx+2:nx+1, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
02399     zds = BDIGITS(z);
02400     if (nx==ny) zds[nx+1] = 0;
02401     while (!yds[ny-1]) ny--;
02402 
02403     dd = 0;
02404     q = yds[ny-1];
02405     while ((q & (BDIGIT)(1UL<<(BITSPERDIG-1))) == 0) {
02406         q <<= 1UL;
02407         dd++;
02408     }
02409     if (dd) {
02410         yy = rb_big_clone(y);
02411         tds = BDIGITS(yy);
02412         j = 0;
02413         t2 = 0;
02414         while (j<ny) {
02415             t2 += (BDIGIT_DBL)yds[j]<<dd;
02416             tds[j++] = BIGLO(t2);
02417             t2 = BIGDN(t2);
02418         }
02419         yds = tds;
02420         RB_GC_GUARD(y) = yy;
02421         j = 0;
02422         t2 = 0;
02423         while (j<nx) {
02424             t2 += (BDIGIT_DBL)xds[j]<<dd;
02425             zds[j++] = BIGLO(t2);
02426             t2 = BIGDN(t2);
02427         }
02428         zds[j] = (BDIGIT)t2;
02429     }
02430     else {
02431         zds[nx] = 0;
02432         j = nx;
02433         while (j--) zds[j] = xds[j];
02434     }
02435 
02436     bds.nx = nx;
02437     bds.ny = ny;
02438     bds.zds = zds;
02439     bds.yds = yds;
02440     bds.stop = Qfalse;
02441     if (nx > 10000 || ny > 10000) {
02442         rb_thread_blocking_region(bigdivrem1, &bds, rb_big_stop, &bds.stop);
02443     }
02444     else {
02445         bigdivrem1(&bds);
02446     }
02447 
02448     if (divp) {                 /* move quotient down in z */
02449         *divp = zz = rb_big_clone(z);
02450         zds = BDIGITS(zz);
02451         j = (nx==ny ? nx+2 : nx+1) - ny;
02452         for (i = 0;i < j;i++) zds[i] = zds[i+ny];
02453         if (!zds[i-1]) i--;
02454         RBIGNUM_SET_LEN(zz, i);
02455     }
02456     if (modp) {                 /* normalize remainder */
02457         *modp = zz = rb_big_clone(z);
02458         zds = BDIGITS(zz);
02459         while (--ny && !zds[ny]); ++ny;
02460         if (dd) {
02461             t2 = 0; i = ny;
02462             while(i--) {
02463                 t2 = (t2 | zds[i]) >> dd;
02464                 q = zds[i];
02465                 zds[i] = BIGLO(t2);
02466                 t2 = BIGUP(q);
02467             }
02468         }
02469         if (!zds[ny-1]) ny--;
02470         RBIGNUM_SET_LEN(zz, ny);
02471         RBIGNUM_SET_SIGN(zz, RBIGNUM_SIGN(x));
02472     }
02473     return z;
02474 }
02475 
02476 static void
02477 bigdivmod(VALUE x, VALUE y, volatile VALUE *divp, volatile VALUE *modp)
02478 {
02479     VALUE mod;
02480 
02481     bigdivrem(x, y, divp, &mod);
02482     if (RBIGNUM_SIGN(x) != RBIGNUM_SIGN(y) && !BIGZEROP(mod)) {
02483         if (divp) *divp = bigadd(*divp, rb_int2big(1), 0);
02484         if (modp) *modp = bigadd(mod, y, 1);
02485     }
02486     else if (modp) {
02487         *modp = mod;
02488     }
02489 }
02490 
02491 
02492 static VALUE
02493 rb_big_divide(VALUE x, VALUE y, ID op)
02494 {
02495     VALUE z;
02496 
02497     switch (TYPE(y)) {
02498       case T_FIXNUM:
02499         y = rb_int2big(FIX2LONG(y));
02500         break;
02501 
02502       case T_BIGNUM:
02503         break;
02504 
02505       case T_FLOAT:
02506         {
02507             double div = rb_big2dbl(x) / RFLOAT_VALUE(y);
02508             if (op == '/') {
02509                 return DBL2NUM(div);
02510             }
02511             else {
02512                 return rb_dbl2big(div);
02513             }
02514         }
02515 
02516       default:
02517         return rb_num_coerce_bin(x, y, op);
02518     }
02519     bigdivmod(x, y, &z, 0);
02520 
02521     return bignorm(z);
02522 }
02523 
02524 /*
02525  *  call-seq:
02526  *     big / other     -> Numeric
02527  *
02528  * Performs division: the class of the resulting object depends on
02529  * the class of <code>numeric</code> and on the magnitude of the
02530  * result.
02531  */
02532 
02533 VALUE
02534 rb_big_div(VALUE x, VALUE y)
02535 {
02536     return rb_big_divide(x, y, '/');
02537 }
02538 
02539 /*
02540  *  call-seq:
02541  *     big.div(other)  -> integer
02542  *
02543  * Performs integer division: returns integer value.
02544  */
02545 
02546 VALUE
02547 rb_big_idiv(VALUE x, VALUE y)
02548 {
02549     return rb_big_divide(x, y, rb_intern("div"));
02550 }
02551 
02552 /*
02553  *  call-seq:
02554  *     big % other         -> Numeric
02555  *     big.modulo(other)   -> Numeric
02556  *
02557  *  Returns big modulo other. See Numeric.divmod for more
02558  *  information.
02559  */
02560 
02561 VALUE
02562 rb_big_modulo(VALUE x, VALUE y)
02563 {
02564     VALUE z;
02565 
02566     switch (TYPE(y)) {
02567       case T_FIXNUM:
02568         y = rb_int2big(FIX2LONG(y));
02569         break;
02570 
02571       case T_BIGNUM:
02572         break;
02573 
02574       default:
02575         return rb_num_coerce_bin(x, y, '%');
02576     }
02577     bigdivmod(x, y, 0, &z);
02578 
02579     return bignorm(z);
02580 }
02581 
02582 /*
02583  *  call-seq:
02584  *     big.remainder(numeric)    -> number
02585  *
02586  *  Returns the remainder after dividing <i>big</i> by <i>numeric</i>.
02587  *
02588  *     -1234567890987654321.remainder(13731)      #=> -6966
02589  *     -1234567890987654321.remainder(13731.24)   #=> -9906.22531493148
02590  */
02591 static VALUE
02592 rb_big_remainder(VALUE x, VALUE y)
02593 {
02594     VALUE z;
02595 
02596     switch (TYPE(y)) {
02597       case T_FIXNUM:
02598         y = rb_int2big(FIX2LONG(y));
02599         break;
02600 
02601       case T_BIGNUM:
02602         break;
02603 
02604       default:
02605         return rb_num_coerce_bin(x, y, rb_intern("remainder"));
02606     }
02607     bigdivrem(x, y, 0, &z);
02608 
02609     return bignorm(z);
02610 }
02611 
02612 /*
02613  *  call-seq:
02614  *     big.divmod(numeric)   -> array
02615  *
02616  *  See <code>Numeric#divmod</code>.
02617  *
02618  */
02619 VALUE
02620 rb_big_divmod(VALUE x, VALUE y)
02621 {
02622     VALUE div, mod;
02623 
02624     switch (TYPE(y)) {
02625       case T_FIXNUM:
02626         y = rb_int2big(FIX2LONG(y));
02627         break;
02628 
02629       case T_BIGNUM:
02630         break;
02631 
02632       default:
02633         return rb_num_coerce_bin(x, y, rb_intern("divmod"));
02634     }
02635     bigdivmod(x, y, &div, &mod);
02636 
02637     return rb_assoc_new(bignorm(div), bignorm(mod));
02638 }
02639 
02640 static int
02641 bdigbitsize(BDIGIT x)
02642 {
02643     int size = 1;
02644     int nb = BITSPERDIG / 2;
02645     BDIGIT bits = (~0 << nb);
02646 
02647     if (!x) return 0;
02648     while (x > 1) {
02649         if (x & bits) {
02650             size += nb;
02651             x >>= nb;
02652         }
02653         x &= ~bits;
02654         nb /= 2;
02655         bits >>= nb;
02656     }
02657 
02658     return size;
02659 }
02660 
02661 static VALUE big_lshift(VALUE, unsigned long);
02662 static VALUE big_rshift(VALUE, unsigned long);
02663 
02664 static VALUE
02665 big_shift(VALUE x, long n)
02666 {
02667     if (n < 0)
02668         return big_lshift(x, (unsigned long)-n);
02669     else if (n > 0)
02670         return big_rshift(x, (unsigned long)n);
02671     return x;
02672 }
02673 
02674 static VALUE
02675 big_fdiv(VALUE x, VALUE y)
02676 {
02677 #define DBL_BIGDIG ((DBL_MANT_DIG + BITSPERDIG) / BITSPERDIG)
02678     VALUE z;
02679     long l, ex, ey;
02680     int i;
02681 
02682     bigtrunc(x);
02683     l = RBIGNUM_LEN(x) - 1;
02684     ex = l * BITSPERDIG;
02685     ex += bdigbitsize(BDIGITS(x)[l]);
02686     ex -= 2 * DBL_BIGDIG * BITSPERDIG;
02687     if (ex) x = big_shift(x, ex);
02688 
02689     switch (TYPE(y)) {
02690       case T_FIXNUM:
02691         y = rb_int2big(FIX2LONG(y));
02692       case T_BIGNUM: {
02693         bigtrunc(y);
02694         l = RBIGNUM_LEN(y) - 1;
02695         ey = l * BITSPERDIG;
02696         ey += bdigbitsize(BDIGITS(y)[l]);
02697         ey -= DBL_BIGDIG * BITSPERDIG;
02698         if (ey) y = big_shift(y, ey);
02699       bignum:
02700         bigdivrem(x, y, &z, 0);
02701         l = ex - ey;
02702 #if SIZEOF_LONG > SIZEOF_INT
02703         {
02704             /* Visual C++ can't be here */
02705             if (l > INT_MAX) return DBL2NUM(INFINITY);
02706             if (l < INT_MIN) return DBL2NUM(0.0);
02707         }
02708 #endif
02709         return DBL2NUM(ldexp(big2dbl(z), (int)l));
02710       }
02711       case T_FLOAT:
02712         y = dbl2big(ldexp(frexp(RFLOAT_VALUE(y), &i), DBL_MANT_DIG));
02713         ey = i - DBL_MANT_DIG;
02714         goto bignum;
02715     }
02716     rb_bug("big_fdiv");
02717     /* NOTREACHED */
02718 }
02719 
02720 /*
02721  *  call-seq:
02722   *     big.fdiv(numeric) -> float
02723  *
02724  *  Returns the floating point result of dividing <i>big</i> by
02725  *  <i>numeric</i>.
02726  *
02727  *     -1234567890987654321.fdiv(13731)      #=> -89910996357705.5
02728  *     -1234567890987654321.fdiv(13731.24)   #=> -89909424858035.7
02729  *
02730  */
02731 
02732 
02733 VALUE
02734 rb_big_fdiv(VALUE x, VALUE y)
02735 {
02736     double dx, dy;
02737 
02738     dx = big2dbl(x);
02739     switch (TYPE(y)) {
02740       case T_FIXNUM:
02741         dy = (double)FIX2LONG(y);
02742         if (isinf(dx))
02743             return big_fdiv(x, y);
02744         break;
02745 
02746       case T_BIGNUM:
02747         dy = rb_big2dbl(y);
02748         if (isinf(dx) || isinf(dy))
02749             return big_fdiv(x, y);
02750         break;
02751 
02752       case T_FLOAT:
02753         dy = RFLOAT_VALUE(y);
02754         if (isnan(dy))
02755             return y;
02756         if (isinf(dx))
02757             return big_fdiv(x, y);
02758         break;
02759 
02760       default:
02761         return rb_num_coerce_bin(x, y, rb_intern("fdiv"));
02762     }
02763     return DBL2NUM(dx / dy);
02764 }
02765 
02766 static VALUE
02767 bigsqr(VALUE x)
02768 {
02769     return bigtrunc(bigmul0(x, x));
02770 }
02771 
02772 /*
02773  *  call-seq:
02774  *     big ** exponent   -> numeric
02775  *
02776  *  Raises _big_ to the _exponent_ power (which may be an integer, float,
02777  *  or anything that will coerce to a number). The result may be
02778  *  a Fixnum, Bignum, or Float
02779  *
02780  *    123456789 ** 2      #=> 15241578750190521
02781  *    123456789 ** 1.2    #=> 5126464716.09932
02782  *    123456789 ** -2     #=> 6.5610001194102e-17
02783  */
02784 
02785 VALUE
02786 rb_big_pow(VALUE x, VALUE y)
02787 {
02788     double d;
02789     SIGNED_VALUE yy;
02790 
02791     if (y == INT2FIX(0)) return INT2FIX(1);
02792     switch (TYPE(y)) {
02793       case T_FLOAT:
02794         d = RFLOAT_VALUE(y);
02795         if ((!RBIGNUM_SIGN(x) && !BIGZEROP(x)) && d != round(d))
02796             return rb_funcall(rb_complex_raw1(x), rb_intern("**"), 1, y);
02797         break;
02798 
02799       case T_BIGNUM:
02800         rb_warn("in a**b, b may be too big");
02801         d = rb_big2dbl(y);
02802         break;
02803 
02804       case T_FIXNUM:
02805         yy = FIX2LONG(y);
02806 
02807         if (yy < 0)
02808             return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
02809         else {
02810             VALUE z = 0;
02811             SIGNED_VALUE mask;
02812             const long BIGLEN_LIMIT = 1024*1024 / SIZEOF_BDIGITS;
02813 
02814             if ((RBIGNUM_LEN(x) > BIGLEN_LIMIT) ||
02815                 (RBIGNUM_LEN(x) > BIGLEN_LIMIT / yy)) {
02816                 rb_warn("in a**b, b may be too big");
02817                 d = (double)yy;
02818                 break;
02819             }
02820             for (mask = FIXNUM_MAX + 1; mask; mask >>= 1) {
02821                 if (z) z = bigsqr(z);
02822                 if (yy & mask) {
02823                     z = z ? bigtrunc(bigmul0(z, x)) : x;
02824                 }
02825             }
02826             return bignorm(z);
02827         }
02828         /* NOTREACHED */
02829         break;
02830 
02831       default:
02832         return rb_num_coerce_bin(x, y, rb_intern("**"));
02833     }
02834     return DBL2NUM(pow(rb_big2dbl(x), d));
02835 }
02836 
02837 static inline VALUE
02838 bit_coerce(VALUE x)
02839 {
02840     while (!FIXNUM_P(x) && TYPE(x) != T_BIGNUM) {
02841         if (TYPE(x) == T_FLOAT) {
02842             rb_raise(rb_eTypeError, "can't convert Float into Integer");
02843         }
02844         x = rb_to_int(x);
02845     }
02846     return x;
02847 }
02848 
02849 static VALUE
02850 bigand_int(VALUE x, long y)
02851 {
02852     VALUE z;
02853     BDIGIT *xds, *zds;
02854     long xn, zn;
02855     long i;
02856     char sign;
02857 
02858     if (y == 0) return INT2FIX(0);
02859     sign = (y > 0);
02860     xds = BDIGITS(x);
02861     zn = xn = RBIGNUM_LEN(x);
02862 #if SIZEOF_BDIGITS == SIZEOF_LONG
02863     if (sign) {
02864         y &= xds[0];
02865         return LONG2NUM(y);
02866     }
02867 #endif
02868 
02869     z = bignew(zn, RBIGNUM_SIGN(x) || sign);
02870     zds = BDIGITS(z);
02871 
02872 #if SIZEOF_BDIGITS == SIZEOF_LONG
02873     i = 1;
02874     zds[0] = xds[0] & y;
02875 #else
02876     {
02877         BDIGIT_DBL num = y;
02878 
02879         for (i=0; i<(int)(sizeof(y)/sizeof(BDIGIT)); i++) {
02880             zds[i] = xds[i] & BIGLO(num);
02881             num = BIGDN(num);
02882         }
02883     }
02884 #endif
02885     while (i < xn) {
02886         zds[i] = sign?0:xds[i];
02887         i++;
02888     }
02889     if (!RBIGNUM_SIGN(z)) get2comp(z);
02890     return bignorm(z);
02891 }
02892 
02893 /*
02894  * call-seq:
02895  *     big & numeric   ->  integer
02896  *
02897  * Performs bitwise +and+ between _big_ and _numeric_.
02898  */
02899 
02900 VALUE
02901 rb_big_and(VALUE xx, VALUE yy)
02902 {
02903     volatile VALUE x, y, z;
02904     BDIGIT *ds1, *ds2, *zds;
02905     long i, l1, l2;
02906     char sign;
02907 
02908     x = xx;
02909     y = bit_coerce(yy);
02910     if (!RBIGNUM_SIGN(x)) {
02911         x = rb_big_clone(x);
02912         get2comp(x);
02913     }
02914     if (FIXNUM_P(y)) {
02915         return bigand_int(x, FIX2LONG(y));
02916     }
02917     if (!RBIGNUM_SIGN(y)) {
02918         y = rb_big_clone(y);
02919         get2comp(y);
02920     }
02921     if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
02922         l1 = RBIGNUM_LEN(y);
02923         l2 = RBIGNUM_LEN(x);
02924         ds1 = BDIGITS(y);
02925         ds2 = BDIGITS(x);
02926         sign = RBIGNUM_SIGN(y);
02927     }
02928     else {
02929         l1 = RBIGNUM_LEN(x);
02930         l2 = RBIGNUM_LEN(y);
02931         ds1 = BDIGITS(x);
02932         ds2 = BDIGITS(y);
02933         sign = RBIGNUM_SIGN(x);
02934     }
02935     z = bignew(l2, RBIGNUM_SIGN(x) || RBIGNUM_SIGN(y));
02936     zds = BDIGITS(z);
02937 
02938     for (i=0; i<l1; i++) {
02939         zds[i] = ds1[i] & ds2[i];
02940     }
02941     for (; i<l2; i++) {
02942         zds[i] = sign?0:ds2[i];
02943     }
02944     if (!RBIGNUM_SIGN(z)) get2comp(z);
02945     return bignorm(z);
02946 }
02947 
02948 static VALUE
02949 bigor_int(VALUE x, long y)
02950 {
02951     VALUE z;
02952     BDIGIT *xds, *zds;
02953     long xn, zn;
02954     long i;
02955     char sign;
02956 
02957     sign = (y >= 0);
02958     xds = BDIGITS(x);
02959     zn = xn = RBIGNUM_LEN(x);
02960     z = bignew(zn, RBIGNUM_SIGN(x) && sign);
02961     zds = BDIGITS(z);
02962 
02963 #if SIZEOF_BDIGITS == SIZEOF_LONG
02964     i = 1;
02965     zds[0] = xds[0] | y;
02966 #else
02967     {
02968         BDIGIT_DBL num = y;
02969 
02970         for (i=0; i<(int)(sizeof(y)/sizeof(BDIGIT)); i++) {
02971             zds[i] = xds[i] | BIGLO(num);
02972             num = BIGDN(num);
02973         }
02974     }
02975 #endif
02976     while (i < xn) {
02977         zds[i] = sign?xds[i]:(BDIGIT)(BIGRAD-1);
02978         i++;
02979     }
02980     if (!RBIGNUM_SIGN(z)) get2comp(z);
02981     return bignorm(z);
02982 }
02983 
02984 /*
02985  * call-seq:
02986  *     big | numeric   ->  integer
02987  *
02988  * Performs bitwise +or+ between _big_ and _numeric_.
02989  */
02990 
02991 VALUE
02992 rb_big_or(VALUE xx, VALUE yy)
02993 {
02994     volatile VALUE x, y, z;
02995     BDIGIT *ds1, *ds2, *zds;
02996     long i, l1, l2;
02997     char sign;
02998 
02999     x = xx;
03000     y = bit_coerce(yy);
03001 
03002     if (!RBIGNUM_SIGN(x)) {
03003         x = rb_big_clone(x);
03004         get2comp(x);
03005     }
03006     if (FIXNUM_P(y)) {
03007         return bigor_int(x, FIX2LONG(y));
03008     }
03009     if (!RBIGNUM_SIGN(y)) {
03010         y = rb_big_clone(y);
03011         get2comp(y);
03012     }
03013     if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
03014         l1 = RBIGNUM_LEN(y);
03015         l2 = RBIGNUM_LEN(x);
03016         ds1 = BDIGITS(y);
03017         ds2 = BDIGITS(x);
03018         sign = RBIGNUM_SIGN(y);
03019     }
03020     else {
03021         l1 = RBIGNUM_LEN(x);
03022         l2 = RBIGNUM_LEN(y);
03023         ds1 = BDIGITS(x);
03024         ds2 = BDIGITS(y);
03025         sign = RBIGNUM_SIGN(x);
03026     }
03027     z = bignew(l2, RBIGNUM_SIGN(x) && RBIGNUM_SIGN(y));
03028     zds = BDIGITS(z);
03029 
03030     for (i=0; i<l1; i++) {
03031         zds[i] = ds1[i] | ds2[i];
03032     }
03033     for (; i<l2; i++) {
03034         zds[i] = sign?ds2[i]:(BDIGIT)(BIGRAD-1);
03035     }
03036     if (!RBIGNUM_SIGN(z)) get2comp(z);
03037     return bignorm(z);
03038 }
03039 
03040 static VALUE
03041 bigxor_int(VALUE x, long y)
03042 {
03043     VALUE z;
03044     BDIGIT *xds, *zds;
03045     long xn, zn;
03046     long i;
03047     char sign;
03048 
03049     sign = (y >= 0) ? 1 : 0;
03050     xds = BDIGITS(x);
03051     zn = xn = RBIGNUM_LEN(x);
03052     z = bignew(zn, !(RBIGNUM_SIGN(x) ^ sign));
03053     zds = BDIGITS(z);
03054 
03055 #if SIZEOF_BDIGITS == SIZEOF_LONG
03056     i = 1;
03057     zds[0] = xds[0] ^ y;
03058 #else
03059     {
03060         BDIGIT_DBL num = y;
03061 
03062         for (i=0; i<(int)(sizeof(y)/sizeof(BDIGIT)); i++) {
03063             zds[i] = xds[i] ^ BIGLO(num);
03064             num = BIGDN(num);
03065         }
03066     }
03067 #endif
03068     while (i < xn) {
03069         zds[i] = sign?xds[i]:~xds[i];
03070         i++;
03071     }
03072     if (!RBIGNUM_SIGN(z)) get2comp(z);
03073     return bignorm(z);
03074 }
03075 /*
03076  * call-seq:
03077  *     big ^ numeric   ->  integer
03078  *
03079  * Performs bitwise +exclusive or+ between _big_ and _numeric_.
03080  */
03081 
03082 VALUE
03083 rb_big_xor(VALUE xx, VALUE yy)
03084 {
03085     volatile VALUE x, y;
03086     VALUE z;
03087     BDIGIT *ds1, *ds2, *zds;
03088     long i, l1, l2;
03089     char sign;
03090 
03091     x = xx;
03092     y = bit_coerce(yy);
03093 
03094     if (!RBIGNUM_SIGN(x)) {
03095         x = rb_big_clone(x);
03096         get2comp(x);
03097     }
03098     if (FIXNUM_P(y)) {
03099         return bigxor_int(x, FIX2LONG(y));
03100     }
03101     if (!RBIGNUM_SIGN(y)) {
03102         y = rb_big_clone(y);
03103         get2comp(y);
03104     }
03105     if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
03106         l1 = RBIGNUM_LEN(y);
03107         l2 = RBIGNUM_LEN(x);
03108         ds1 = BDIGITS(y);
03109         ds2 = BDIGITS(x);
03110         sign = RBIGNUM_SIGN(y);
03111     }
03112     else {
03113         l1 = RBIGNUM_LEN(x);
03114         l2 = RBIGNUM_LEN(y);
03115         ds1 = BDIGITS(x);
03116         ds2 = BDIGITS(y);
03117         sign = RBIGNUM_SIGN(x);
03118     }
03119     RBIGNUM_SET_SIGN(x, RBIGNUM_SIGN(x)?1:0);
03120     RBIGNUM_SET_SIGN(y, RBIGNUM_SIGN(y)?1:0);
03121     z = bignew(l2, !(RBIGNUM_SIGN(x) ^ RBIGNUM_SIGN(y)));
03122     zds = BDIGITS(z);
03123 
03124     for (i=0; i<l1; i++) {
03125         zds[i] = ds1[i] ^ ds2[i];
03126     }
03127     for (; i<l2; i++) {
03128         zds[i] = sign?ds2[i]:~ds2[i];
03129     }
03130     if (!RBIGNUM_SIGN(z)) get2comp(z);
03131 
03132     return bignorm(z);
03133 }
03134 
03135 static VALUE
03136 check_shiftdown(VALUE y, VALUE x)
03137 {
03138     if (!RBIGNUM_LEN(x)) return INT2FIX(0);
03139     if (RBIGNUM_LEN(y) > SIZEOF_LONG / SIZEOF_BDIGITS) {
03140         return RBIGNUM_SIGN(x) ? INT2FIX(0) : INT2FIX(-1);
03141     }
03142     return Qnil;
03143 }
03144 
03145 /*
03146  * call-seq:
03147  *     big << numeric   ->  integer
03148  *
03149  * Shifts big left _numeric_ positions (right if _numeric_ is negative).
03150  */
03151 
03152 VALUE
03153 rb_big_lshift(VALUE x, VALUE y)
03154 {
03155     long shift;
03156     int neg = 0;
03157 
03158     for (;;) {
03159         if (FIXNUM_P(y)) {
03160             shift = FIX2LONG(y);
03161             if (shift < 0) {
03162                 neg = 1;
03163                 shift = -shift;
03164             }
03165             break;
03166         }
03167         else if (TYPE(y) == T_BIGNUM) {
03168             if (!RBIGNUM_SIGN(y)) {
03169                 VALUE t = check_shiftdown(y, x);
03170                 if (!NIL_P(t)) return t;
03171                 neg = 1;
03172             }
03173             shift = big2ulong(y, "long", TRUE);
03174             break;
03175         }
03176         y = rb_to_int(y);
03177     }
03178 
03179     x = neg ? big_rshift(x, shift) : big_lshift(x, shift);
03180     return bignorm(x);
03181 }
03182 
03183 static VALUE
03184 big_lshift(VALUE x, unsigned long shift)
03185 {
03186     BDIGIT *xds, *zds;
03187     long s1 = shift/BITSPERDIG;
03188     int s2 = (int)(shift%BITSPERDIG);
03189     VALUE z;
03190     BDIGIT_DBL num = 0;
03191     long len, i;
03192 
03193     len = RBIGNUM_LEN(x);
03194     z = bignew(len+s1+1, RBIGNUM_SIGN(x));
03195     zds = BDIGITS(z);
03196     for (i=0; i<s1; i++) {
03197         *zds++ = 0;
03198     }
03199     xds = BDIGITS(x);
03200     for (i=0; i<len; i++) {
03201         num = num | (BDIGIT_DBL)*xds++<<s2;
03202         *zds++ = BIGLO(num);
03203         num = BIGDN(num);
03204     }
03205     *zds = BIGLO(num);
03206     return z;
03207 }
03208 
03209 /*
03210  * call-seq:
03211  *     big >> numeric   ->  integer
03212  *
03213  * Shifts big right _numeric_ positions (left if _numeric_ is negative).
03214  */
03215 
03216 VALUE
03217 rb_big_rshift(VALUE x, VALUE y)
03218 {
03219     long shift;
03220     int neg = 0;
03221 
03222     for (;;) {
03223         if (FIXNUM_P(y)) {
03224             shift = FIX2LONG(y);
03225             if (shift < 0) {
03226                 neg = 1;
03227                 shift = -shift;
03228             }
03229             break;
03230         }
03231         else if (TYPE(y) == T_BIGNUM) {
03232             if (RBIGNUM_SIGN(y)) {
03233                 VALUE t = check_shiftdown(y, x);
03234                 if (!NIL_P(t)) return t;
03235             }
03236             else {
03237                 neg = 1;
03238             }
03239             shift = big2ulong(y, "long", TRUE);
03240             break;
03241         }
03242         y = rb_to_int(y);
03243     }
03244 
03245     x = neg ? big_lshift(x, shift) : big_rshift(x, shift);
03246     return bignorm(x);
03247 }
03248 
03249 static VALUE
03250 big_rshift(VALUE x, unsigned long shift)
03251 {
03252     BDIGIT *xds, *zds;
03253     long s1 = shift/BITSPERDIG;
03254     int s2 = (int)(shift%BITSPERDIG);
03255     VALUE z;
03256     BDIGIT_DBL num = 0;
03257     long i, j;
03258     volatile VALUE save_x;
03259 
03260     if (s1 > RBIGNUM_LEN(x)) {
03261         if (RBIGNUM_SIGN(x))
03262             return INT2FIX(0);
03263         else
03264             return INT2FIX(-1);
03265     }
03266     if (!RBIGNUM_SIGN(x)) {
03267         save_x = x = rb_big_clone(x);
03268         get2comp(x);
03269     }
03270     xds = BDIGITS(x);
03271     i = RBIGNUM_LEN(x); j = i - s1;
03272     if (j == 0) {
03273         if (RBIGNUM_SIGN(x)) return INT2FIX(0);
03274         else return INT2FIX(-1);
03275     }
03276     z = bignew(j, RBIGNUM_SIGN(x));
03277     if (!RBIGNUM_SIGN(x)) {
03278         num = ((BDIGIT_DBL)~0) << BITSPERDIG;
03279     }
03280     zds = BDIGITS(z);
03281     while (i--, j--) {
03282         num = (num | xds[i]) >> s2;
03283         zds[j] = BIGLO(num);
03284         num = BIGUP(xds[i]);
03285     }
03286     if (!RBIGNUM_SIGN(x)) {
03287         get2comp(z);
03288     }
03289     return z;
03290 }
03291 
03292 /*
03293  *  call-seq:
03294  *     big[n] -> 0, 1
03295  *
03296  *  Bit Reference---Returns the <em>n</em>th bit in the (assumed) binary
03297  *  representation of <i>big</i>, where <i>big</i>[0] is the least
03298  *  significant bit.
03299  *
03300  *     a = 9**15
03301  *     50.downto(0) do |n|
03302  *       print a[n]
03303  *     end
03304  *
03305  *  <em>produces:</em>
03306  *
03307  *     000101110110100000111000011110010100111100010111001
03308  *
03309  */
03310 
03311 static VALUE
03312 rb_big_aref(VALUE x, VALUE y)
03313 {
03314     BDIGIT *xds;
03315     BDIGIT_DBL num;
03316     VALUE shift;
03317     long i, s1, s2;
03318 
03319     if (TYPE(y) == T_BIGNUM) {
03320         if (!RBIGNUM_SIGN(y))
03321             return INT2FIX(0);
03322         bigtrunc(y);
03323         if (RBIGNUM_LEN(y) > DIGSPERLONG) {
03324           out_of_range:
03325             return RBIGNUM_SIGN(x) ? INT2FIX(0) : INT2FIX(1);
03326         }
03327         shift = big2ulong(y, "long", FALSE);
03328     }
03329     else {
03330         i = NUM2LONG(y);
03331         if (i < 0) return INT2FIX(0);
03332         shift = (VALUE)i;
03333     }
03334     s1 = shift/BITSPERDIG;
03335     s2 = shift%BITSPERDIG;
03336 
03337     if (s1 >= RBIGNUM_LEN(x)) goto out_of_range;
03338     if (!RBIGNUM_SIGN(x)) {
03339         xds = BDIGITS(x);
03340         i = 0; num = 1;
03341         while (num += ~xds[i], ++i <= s1) {
03342             num = BIGDN(num);
03343         }
03344     }
03345     else {
03346         num = BDIGITS(x)[s1];
03347     }
03348     if (num & ((BDIGIT_DBL)1<<s2))
03349         return INT2FIX(1);
03350     return INT2FIX(0);
03351 }
03352 
03353 /*
03354  * call-seq:
03355  *   big.hash   -> fixnum
03356  *
03357  * Compute a hash based on the value of _big_.
03358  */
03359 
03360 static VALUE
03361 rb_big_hash(VALUE x)
03362 {
03363     st_index_t hash;
03364 
03365     hash = rb_memhash(BDIGITS(x), sizeof(BDIGIT)*RBIGNUM_LEN(x)) ^ RBIGNUM_SIGN(x);
03366     return INT2FIX(hash);
03367 }
03368 
03369 /*
03370  * MISSING: documentation
03371  */
03372 
03373 static VALUE
03374 rb_big_coerce(VALUE x, VALUE y)
03375 {
03376     if (FIXNUM_P(y)) {
03377         return rb_assoc_new(rb_int2big(FIX2LONG(y)), x);
03378     }
03379     else if (TYPE(y) == T_BIGNUM) {
03380        return rb_assoc_new(y, x);
03381     }
03382     else {
03383         rb_raise(rb_eTypeError, "can't coerce %s to Bignum",
03384                  rb_obj_classname(y));
03385     }
03386     /* not reached */
03387     return Qnil;
03388 }
03389 
03390 /*
03391  *  call-seq:
03392  *     big.abs -> aBignum
03393  *
03394  *  Returns the absolute value of <i>big</i>.
03395  *
03396  *     -1234567890987654321.abs   #=> 1234567890987654321
03397  */
03398 
03399 static VALUE
03400 rb_big_abs(VALUE x)
03401 {
03402     if (!RBIGNUM_SIGN(x)) {
03403         x = rb_big_clone(x);
03404         RBIGNUM_SET_SIGN(x, 1);
03405     }
03406     return x;
03407 }
03408 
03409 /*
03410  *  call-seq:
03411  *     big.size -> integer
03412  *
03413  *  Returns the number of bytes in the machine representation of
03414  *  <i>big</i>.
03415  *
03416  *     (256**10 - 1).size   #=> 12
03417  *     (256**20 - 1).size   #=> 20
03418  *     (256**40 - 1).size   #=> 40
03419  */
03420 
03421 static VALUE
03422 rb_big_size(VALUE big)
03423 {
03424     return LONG2FIX(RBIGNUM_LEN(big)*SIZEOF_BDIGITS);
03425 }
03426 
03427 /*
03428  *  call-seq:
03429  *     big.odd? -> true or false
03430  *
03431  *  Returns <code>true</code> if <i>big</i> is an odd number.
03432  */
03433 
03434 static VALUE
03435 rb_big_odd_p(VALUE num)
03436 {
03437     if (BDIGITS(num)[0] & 1) {
03438         return Qtrue;
03439     }
03440     return Qfalse;
03441 }
03442 
03443 /*
03444  *  call-seq:
03445  *     big.even? -> true or false
03446  *
03447  *  Returns <code>true</code> if <i>big</i> is an even number.
03448  */
03449 
03450 static VALUE
03451 rb_big_even_p(VALUE num)
03452 {
03453     if (BDIGITS(num)[0] & 1) {
03454         return Qfalse;
03455     }
03456     return Qtrue;
03457 }
03458 
03459 /*
03460  *  Bignum objects hold integers outside the range of
03461  *  Fixnum. Bignum objects are created
03462  *  automatically when integer calculations would otherwise overflow a
03463  *  Fixnum. When a calculation involving
03464  *  Bignum objects returns a result that will fit in a
03465  *  Fixnum, the result is automatically converted.
03466  *
03467  *  For the purposes of the bitwise operations and <code>[]</code>, a
03468  *  Bignum is treated as if it were an infinite-length
03469  *  bitstring with 2's complement representation.
03470  *
03471  *  While Fixnum values are immediate, Bignum
03472  *  objects are not---assignment and parameter passing work with
03473  *  references to objects, not the objects themselves.
03474  *
03475  */
03476 
03477 void
03478 Init_Bignum(void)
03479 {
03480     rb_cBignum = rb_define_class("Bignum", rb_cInteger);
03481 
03482     rb_define_method(rb_cBignum, "to_s", rb_big_to_s, -1);
03483     rb_define_method(rb_cBignum, "coerce", rb_big_coerce, 1);
03484     rb_define_method(rb_cBignum, "-@", rb_big_uminus, 0);
03485     rb_define_method(rb_cBignum, "+", rb_big_plus, 1);
03486     rb_define_method(rb_cBignum, "-", rb_big_minus, 1);
03487     rb_define_method(rb_cBignum, "*", rb_big_mul, 1);
03488     rb_define_method(rb_cBignum, "/", rb_big_div, 1);
03489     rb_define_method(rb_cBignum, "%", rb_big_modulo, 1);
03490     rb_define_method(rb_cBignum, "div", rb_big_idiv, 1);
03491     rb_define_method(rb_cBignum, "divmod", rb_big_divmod, 1);
03492     rb_define_method(rb_cBignum, "modulo", rb_big_modulo, 1);
03493     rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1);
03494     rb_define_method(rb_cBignum, "fdiv", rb_big_fdiv, 1);
03495     rb_define_method(rb_cBignum, "**", rb_big_pow, 1);
03496     rb_define_method(rb_cBignum, "&", rb_big_and, 1);
03497     rb_define_method(rb_cBignum, "|", rb_big_or, 1);
03498     rb_define_method(rb_cBignum, "^", rb_big_xor, 1);
03499     rb_define_method(rb_cBignum, "~", rb_big_neg, 0);
03500     rb_define_method(rb_cBignum, "<<", rb_big_lshift, 1);
03501     rb_define_method(rb_cBignum, ">>", rb_big_rshift, 1);
03502     rb_define_method(rb_cBignum, "[]", rb_big_aref, 1);
03503 
03504     rb_define_method(rb_cBignum, "<=>", rb_big_cmp, 1);
03505     rb_define_method(rb_cBignum, "==", rb_big_eq, 1);
03506     rb_define_method(rb_cBignum, ">", big_gt, 1);
03507     rb_define_method(rb_cBignum, ">=", big_ge, 1);
03508     rb_define_method(rb_cBignum, "<", big_lt, 1);
03509     rb_define_method(rb_cBignum, "<=", big_le, 1);
03510     rb_define_method(rb_cBignum, "===", rb_big_eq, 1);
03511     rb_define_method(rb_cBignum, "eql?", rb_big_eql, 1);
03512     rb_define_method(rb_cBignum, "hash", rb_big_hash, 0);
03513     rb_define_method(rb_cBignum, "to_f", rb_big_to_f, 0);
03514     rb_define_method(rb_cBignum, "abs", rb_big_abs, 0);
03515     rb_define_method(rb_cBignum, "magnitude", rb_big_abs, 0);
03516     rb_define_method(rb_cBignum, "size", rb_big_size, 0);
03517     rb_define_method(rb_cBignum, "odd?", rb_big_odd_p, 0);
03518     rb_define_method(rb_cBignum, "even?", rb_big_even_p, 0);
03519 
03520     power_cache_init();
03521 }
03522 

Generated on Wed Aug 10 09:13:58 2011 for Ruby by  doxygen 1.4.7