Bignum objects hold integers outside the range of Fixnum. Bignum objects are created automatically when integer calculations would otherwise overflow a Fixnum. When a calculation involving Bignum objects returns a result that will fit in a Fixnum, the result is automatically converted.
For the purposes of the bitwise operations and []
, a Bignum is treated as if it were an infinite-length
bitstring with 2's complement representation.
While Fixnum values are immediate, Bignum objects are not—assignment and parameter passing work with references to objects, not the objects themselves.
Returns big modulo other. See Numeric#divmod for more information.
static VALUE rb_big_modulo(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(x, y); } bigdivmod(x, y, 0, &z); return bignorm(z); }
Performs bitwise and
between big and
numeric.
VALUE rb_big_and(xx, yy) VALUE xx, yy; { volatile VALUE x, y, z; BDIGIT *ds1, *ds2, *zds; long i, l1, l2; char sign; x = xx; y = rb_to_int(yy); if (FIXNUM_P(y)) { y = rb_int2big(FIX2LONG(y)); } if (!RBIGNUM(y)->sign) { y = rb_big_clone(y); get2comp(y); } if (!RBIGNUM(x)->sign) { x = rb_big_clone(x); get2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; l2 = RBIGNUM(x)->len; ds1 = BDIGITS(y); ds2 = BDIGITS(x); sign = RBIGNUM(y)->sign; } else { l1 = RBIGNUM(x)->len; l2 = RBIGNUM(y)->len; ds1 = BDIGITS(x); ds2 = BDIGITS(y); sign = RBIGNUM(x)->sign; } z = bignew(l2, RBIGNUM(x)->sign || RBIGNUM(y)->sign); zds = BDIGITS(z); for (i=0; i<l1; i++) { zds[i] = ds1[i] & ds2[i]; } for (; i<l2; i++) { zds[i] = sign?0:ds2[i]; } if (!RBIGNUM(z)->sign) get2comp(z); return bignorm(z); }
Multiplies big and other, returning the result.
VALUE rb_big_mul(x, y) VALUE x, y; { return bignorm(rb_big_mul0(x, y)); }
Raises big to the exponent power (which may be an integer, float, or anything that will coerce to a number). The result may be a Fixnum, Bignum, or Float
123456789 ** 2 #=> 15241578750190521 123456789 ** 1.2 #=> 5126464716.09932 123456789 ** -2 #=> 6.5610001194102e-17
VALUE rb_big_pow(x, y) VALUE x, y; { double d; long yy; if (y == INT2FIX(0)) return INT2FIX(1); switch (TYPE(y)) { case T_FLOAT: d = RFLOAT(y)->value; break; case T_BIGNUM: rb_warn("in a**b, b may be too big"); d = rb_big2dbl(y); break; case T_FIXNUM: yy = FIX2LONG(y); if (yy > 0) { VALUE z = x; const long BIGLEN_LIMIT = 1024*1024 / SIZEOF_BDIGITS; if ((RBIGNUM(x)->len > BIGLEN_LIMIT) || (RBIGNUM(x)->len > BIGLEN_LIMIT / yy)) { rb_warn("in a**b, b may be too big"); d = (double)yy; break; } for (;;) { yy -= 1; if (yy == 0) break; while (yy % 2 == 0) { yy /= 2; x = rb_big_mul0(x, x); bigtrunc(x); } z = rb_big_mul0(z, x); bigtrunc(z); } return bignorm(z); } d = (double)yy; break; default: return rb_num_coerce_bin(x, y); } return rb_float_new(pow(rb_big2dbl(x), d)); }
Adds big and other, returning the result.
VALUE rb_big_plus(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); /* fall through */ case T_BIGNUM: return bignorm(bigadd(x, y, 1)); case T_FLOAT: return rb_float_new(rb_big2dbl(x) + RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } }
Subtracts other from big, returning the result.
VALUE rb_big_minus(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); /* fall through */ case T_BIGNUM: return bignorm(bigadd(x, y, 0)); case T_FLOAT: return rb_float_new(rb_big2dbl(x) - RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } }
Unary minus (returns a new Bignum whose value is 0-big)
static VALUE rb_big_uminus(x) VALUE x; { VALUE z = rb_big_clone(x); RBIGNUM(z)->sign = !RBIGNUM(x)->sign; return bignorm(z); }
Divides big by other, returning the result.
static VALUE rb_big_div(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: return rb_float_new(rb_big2dbl(x) / RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } bigdivmod(x, y, &z, 0); return bignorm(z); }
Shifts big left numeric positions (right if numeric is negative).
VALUE rb_big_lshift(x, y) VALUE x, y; { long shift; int neg = 0; for (;;) { if (FIXNUM_P(y)) { shift = FIX2LONG(y); if (shift < 0) { neg = 1; shift = -shift; } break; } else if (TYPE(y) == T_BIGNUM) { if (!RBIGNUM(y)->sign) { VALUE t = check_shiftdown(y, x); if (!NIL_P(t)) return t; neg = 1; } shift = big2ulong(y, "long", Qtrue); break; } y = rb_to_int(y); } if (neg) return big_rshift(x, shift); return big_lshift(x, shift); }
Comparison—Returns -1, 0, or +1 depending on whether big is less
than, equal to, or greater than numeric. This is the basis for the
tests in Comparable
.
static VALUE rb_big_cmp(x, y) VALUE x, y; { long xlen = RBIGNUM(x)->len; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: { double a = RFLOAT(y)->value; if (isinf(a)) { if (a > 0.0) return INT2FIX(-1); else return INT2FIX(1); } return rb_dbl_cmp(rb_big2dbl(x), a); } default: return rb_num_coerce_cmp(x, y); } if (RBIGNUM(x)->sign > RBIGNUM(y)->sign) return INT2FIX(1); if (RBIGNUM(x)->sign < RBIGNUM(y)->sign) return INT2FIX(-1); if (xlen < RBIGNUM(y)->len) return (RBIGNUM(x)->sign) ? INT2FIX(-1) : INT2FIX(1); if (xlen > RBIGNUM(y)->len) return (RBIGNUM(x)->sign) ? INT2FIX(1) : INT2FIX(-1); while(xlen-- && (BDIGITS(x)[xlen]==BDIGITS(y)[xlen])); if (-1 == xlen) return INT2FIX(0); return (BDIGITS(x)[xlen] > BDIGITS(y)[xlen]) ? (RBIGNUM(x)->sign ? INT2FIX(1) : INT2FIX(-1)) : (RBIGNUM(x)->sign ? INT2FIX(-1) : INT2FIX(1)); }
Returns true
only if obj has the same value as
big. Contrast this with Bignum#eql?
, which requires
obj to be a Bignum
.
68719476736 == 68719476736.0 #=> true
static VALUE rb_big_eq(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: { volatile double a, b; a = RFLOAT(y)->value; if (isnan(a)) return Qfalse; b = rb_big2dbl(x); return (a == b)?Qtrue:Qfalse; } default: return rb_equal(y, x); } if (RBIGNUM(x)->sign != RBIGNUM(y)->sign) return Qfalse; if (RBIGNUM(x)->len != RBIGNUM(y)->len) return Qfalse; if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM(y)->len) != 0) return Qfalse; return Qtrue; }
Shifts big right numeric positions (left if numeric is negative).
VALUE rb_big_rshift(x, y) VALUE x, y; { long shift; int neg = 0; for (;;) { if (FIXNUM_P(y)) { shift = FIX2LONG(y); if (shift < 0) { neg = 1; shift = -shift; } break; } else if (TYPE(y) == T_BIGNUM) { if (RBIGNUM(y)->sign) { VALUE t = check_shiftdown(y, x); if (!NIL_P(t)) return t; } else { neg = 1; } shift = big2ulong(y, "long", Qtrue); break; } y = rb_to_int(y); } if (neg) return big_lshift(x, shift); return big_rshift(x, shift); }
Bit Reference—Returns the nth bit in the (assumed) binary representation of big, where big is the least significant bit.
a = 9**15 50.downto(0) do |n| print a[n] end
produces:
000101110110100000111000011110010100111100010111001
static VALUE rb_big_aref(x, y) VALUE x, y; { BDIGIT *xds; BDIGIT_DBL num; unsigned long shift; long i, s1, s2; if (TYPE(y) == T_BIGNUM) { if (!RBIGNUM(y)->sign) return INT2FIX(0); if (RBIGNUM(bigtrunc(y))->len > SIZEOF_LONG/SIZEOF_BDIGITS) { out_of_range: return RBIGNUM(x)->sign ? INT2FIX(0) : INT2FIX(1); } shift = big2ulong(y, "long", Qfalse); } else { i = NUM2LONG(y); if (i < 0) return INT2FIX(0); shift = (VALUE)i; } s1 = shift/BITSPERDIG; s2 = shift%BITSPERDIG; if (s1 >= RBIGNUM(x)->len) goto out_of_range; if (!RBIGNUM(x)->sign) { xds = BDIGITS(x); i = 0; num = 1; while (num += ~xds[i], ++i <= s1) { num = BIGDN(num); } } else { num = BDIGITS(x)[s1]; } if (num & ((BDIGIT_DBL)1<<s2)) return INT2FIX(1); return INT2FIX(0); }
Performs bitwise +exclusive or+ between big and numeric.
VALUE rb_big_xor(xx, yy) VALUE xx, yy; { volatile VALUE x, y; VALUE z; BDIGIT *ds1, *ds2, *zds; long i, l1, l2; char sign; x = xx; y = rb_to_int(yy); if (FIXNUM_P(y)) { y = rb_int2big(FIX2LONG(y)); } if (!RBIGNUM(y)->sign) { y = rb_big_clone(y); get2comp(y); } if (!RBIGNUM(x)->sign) { x = rb_big_clone(x); get2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; l2 = RBIGNUM(x)->len; ds1 = BDIGITS(y); ds2 = BDIGITS(x); sign = RBIGNUM(y)->sign; } else { l1 = RBIGNUM(x)->len; l2 = RBIGNUM(y)->len; ds1 = BDIGITS(x); ds2 = BDIGITS(y); sign = RBIGNUM(x)->sign; } RBIGNUM(x)->sign = RBIGNUM(x)->sign?1:0; RBIGNUM(y)->sign = RBIGNUM(y)->sign?1:0; z = bignew(l2, !(RBIGNUM(x)->sign ^ RBIGNUM(y)->sign)); zds = BDIGITS(z); for (i=0; i<l1; i++) { zds[i] = ds1[i] ^ ds2[i]; } for (; i<l2; i++) { zds[i] = sign?ds2[i]:~ds2[i]; } if (!RBIGNUM(z)->sign) get2comp(z); return bignorm(z); }
Returns the absolute value of big.
-1234567890987654321.abs #=> 1234567890987654321
static VALUE rb_big_abs(x) VALUE x; { if (!RBIGNUM(x)->sign) { x = rb_big_clone(x); RBIGNUM(x)->sign = 1; } return x; }
MISSING: documentation
static VALUE rb_big_coerce(x, y) VALUE x, y; { if (FIXNUM_P(y)) { return rb_assoc_new(rb_int2big(FIX2LONG(y)), x); } else if (TYPE(y) == T_BIGNUM) { return rb_assoc_new(y, x); } else { rb_raise(rb_eTypeError, "can't coerce %s to Bignum", rb_obj_classname(y)); } /* not reached */ return Qnil; }
Divides big by other, returning the result.
static VALUE rb_big_div(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: return rb_float_new(rb_big2dbl(x) / RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); } bigdivmod(x, y, &z, 0); return bignorm(z); }
See Numeric#divmod
.
VALUE rb_big_divmod(x, y) VALUE x, y; { VALUE div, mod; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(x, y); } bigdivmod(x, y, &div, &mod); return rb_assoc_new(bignorm(div), bignorm(mod)); }
Returns true
only if obj is a Bignum
with the same value as big. Contrast this with
Bignum#==
, which performs type conversions.
68719476736.eql?(68719476736.0) #=> false
static VALUE rb_big_eql(x, y) VALUE x, y; { if (TYPE(y) != T_BIGNUM) return Qfalse; if (RBIGNUM(x)->sign != RBIGNUM(y)->sign) return Qfalse; if (RBIGNUM(x)->len != RBIGNUM(y)->len) return Qfalse; if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,RBIGNUM(y)->len) != 0) return Qfalse; return Qtrue; }
Compute a hash based on the value of big.
static VALUE rb_big_hash(x) VALUE x; { long i, len, key; BDIGIT *digits; key = 0; digits = BDIGITS(x); len = RBIGNUM(x)->len; for (i=0; i<len; i++) { key ^= *digits++; } return LONG2FIX(key); }
Returns big modulo other. See Numeric#divmod for more information.
static VALUE rb_big_modulo(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(x, y); } bigdivmod(x, y, 0, &z); return bignorm(z); }
Returns the floating point result of dividing big by numeric.
-1234567890987654321.quo(13731) #=> -89910996357705.5 -1234567890987654321.quo(13731.24) #=> -89909424858035.7
static VALUE rb_big_quo(x, y) VALUE x, y; { double dx = rb_big2dbl(x); double dy; switch (TYPE(y)) { case T_FIXNUM: dy = (double)FIX2LONG(y); break; case T_BIGNUM: dy = rb_big2dbl(y); break; case T_FLOAT: dy = RFLOAT(y)->value; break; default: return rb_num_coerce_bin(x, y); } return rb_float_new(dx / dy); }
Returns the remainder after dividing big by numeric.
-1234567890987654321.remainder(13731) #=> -6966 -1234567890987654321.remainder(13731.24) #=> -9906.22531493148
static VALUE rb_big_remainder(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(x, y); } bigdivrem(x, y, 0, &z); return bignorm(z); }
Returns the number of bytes in the machine representation of big.
(256**10 - 1).size #=> 12 (256**20 - 1).size #=> 20 (256**40 - 1).size #=> 40
static VALUE rb_big_size(big) VALUE big; { return LONG2FIX(RBIGNUM(big)->len*SIZEOF_BDIGITS); }
Converts big to a Float
. If big doesn't
fit in a Float
, the result is infinity.
static VALUE rb_big_to_f(x) VALUE x; { return rb_float_new(rb_big2dbl(x)); }
Returns a string containing the representation of big radix base (2 through 36).
12345654321.to_s #=> "12345654321" 12345654321.to_s(2) #=> "1011011111110110111011110000110001" 12345654321.to_s(8) #=> "133766736061" 12345654321.to_s(16) #=> "2dfdbbc31" 78546939656932.to_s(36) #=> "rubyrules"
static VALUE rb_big_to_s(argc, argv, x) int argc; VALUE *argv; VALUE x; { VALUE b; int base; rb_scan_args(argc, argv, "01", &b); if (argc == 0) base = 10; else base = NUM2INT(b); return rb_big2str(x, base); }
Performs bitwise or
between big and numeric.
VALUE rb_big_or(xx, yy) VALUE xx, yy; { volatile VALUE x, y, z; BDIGIT *ds1, *ds2, *zds; long i, l1, l2; char sign; x = xx; y = rb_to_int(yy); if (FIXNUM_P(y)) { y = rb_int2big(FIX2LONG(y)); } if (!RBIGNUM(y)->sign) { y = rb_big_clone(y); get2comp(y); } if (!RBIGNUM(x)->sign) { x = rb_big_clone(x); get2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; l2 = RBIGNUM(x)->len; ds1 = BDIGITS(y); ds2 = BDIGITS(x); sign = RBIGNUM(y)->sign; } else { l1 = RBIGNUM(x)->len; l2 = RBIGNUM(y)->len; ds1 = BDIGITS(x); ds2 = BDIGITS(y); sign = RBIGNUM(x)->sign; } z = bignew(l2, RBIGNUM(x)->sign && RBIGNUM(y)->sign); zds = BDIGITS(z); for (i=0; i<l1; i++) { zds[i] = ds1[i] | ds2[i]; } for (; i<l2; i++) { zds[i] = sign?ds2[i]:(BIGRAD-1); } if (!RBIGNUM(z)->sign) get2comp(z); return bignorm(z); }
Inverts the bits in big. As Bignums are conceptually infinite length, the result acts as if it had an infinite number of one bits to the left. In hex representations, this is displayed as two periods to the left of the digits.
sprintf("%X", ~0x1122334455) #=> "..FEEDDCCBBAA"
static VALUE rb_big_neg(x) VALUE x; { VALUE z = rb_big_clone(x); long i; BDIGIT *ds; if (!RBIGNUM(x)->sign) get2comp(z); ds = BDIGITS(z); i = RBIGNUM(x)->len; if (!i) return INT2FIX(~0); while (i--) ds[i] = ~ds[i]; RBIGNUM(z)->sign = !RBIGNUM(z)->sign; if (RBIGNUM(x)->sign) get2comp(z); return bignorm(z); }