summaryrefslogtreecommitdiff
path: root/bignum.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-05-27 16:16:57 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-05-27 16:16:57 +0000
commit80ad1473cfefea77b4964d285fcae8ff5a4cac4b (patch)
treef922ef51a052288a9e49c20d87ec15bdafb0a604 /bignum.c
parent72f4e2c7098df4093d1fcf6dabca2655fcd8fef9 (diff)
* bignum.c (bigand_int): new function to calculate bignum and
fixnum without allocating internal bignum. * bignum.c (bigor_int): ditto. * bignum.c (bigxor_int): ditto. * bignum.c (bigand_int): even less object allocation. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23596 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'bignum.c')
-rw-r--r--bignum.c152
1 files changed, 133 insertions, 19 deletions
diff --git a/bignum.c b/bignum.c
index ab7b5f7553..398d963aea 100644
--- a/bignum.c
+++ b/bignum.c
@@ -2530,7 +2530,7 @@ rb_big_pow(VALUE x, VALUE y)
return DBL2NUM(pow(rb_big2dbl(x), d));
}
-static VALUE
+static inline VALUE
bit_coerce(VALUE x)
{
while (!FIXNUM_P(x) && TYPE(x) != T_BIGNUM) {
@@ -2542,6 +2542,50 @@ bit_coerce(VALUE x)
return x;
}
+static VALUE
+bigand_int(VALUE x, long y)
+{
+ VALUE z;
+ BDIGIT *xds, *zds;
+ long xn, zn;
+ long i;
+ char sign;
+
+ if (y == 0) return INT2FIX(0);
+ sign = (y > 0);
+ xds = BDIGITS(x);
+ zn = xn = RBIGNUM_LEN(x);
+#if SIZEOF_BDIGITS == SIZEOF_LONG
+ if (sign) {
+ y &= xds[0];
+ return LONG2NUM(y);
+ }
+#endif
+
+ z = bignew(zn, RBIGNUM_SIGN(x) || sign);
+ zds = BDIGITS(z);
+
+#if SIZEOF_BDIGITS == SIZEOF_LONG
+ i = 1;
+ zds[0] = xds[0] & y;
+#else
+ {
+ BDIGIT_DBL num = y;
+
+ for (i=0; i<(int)(sizeof(y)/sizeof(BDIGIT)); i++) {
+ zds[i] = xds[i] & BIGLO(num);
+ num = BIGDN(num);
+ }
+ }
+#endif
+ while (i < xn) {
+ zds[i] = sign?0:xds[i];
+ i++;
+ }
+ if (!RBIGNUM_SIGN(z)) get2comp(z);
+ return bignorm(z);
+}
+
/*
* call-seq:
* big & numeric => integer
@@ -2559,17 +2603,17 @@ rb_big_and(VALUE xx, VALUE yy)
x = xx;
y = bit_coerce(yy);
+ if (!RBIGNUM_SIGN(x)) {
+ x = rb_big_clone(x);
+ get2comp(x);
+ }
if (FIXNUM_P(y)) {
- y = rb_int2big(FIX2LONG(y));
+ return bigand_int(x, FIX2LONG(y));
}
if (!RBIGNUM_SIGN(y)) {
y = rb_big_clone(y);
get2comp(y);
}
- if (!RBIGNUM_SIGN(x)) {
- x = rb_big_clone(x);
- get2comp(x);
- }
if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
l1 = RBIGNUM_LEN(y);
l2 = RBIGNUM_LEN(x);
@@ -2597,6 +2641,42 @@ rb_big_and(VALUE xx, VALUE yy)
return bignorm(z);
}
+static VALUE
+bigor_int(VALUE x, long y)
+{
+ VALUE z;
+ BDIGIT *xds, *zds;
+ long xn, zn;
+ long i;
+ char sign;
+
+ sign = (y >= 0);
+ xds = BDIGITS(x);
+ zn = xn = RBIGNUM_LEN(x);
+ z = bignew(zn, RBIGNUM_SIGN(x) && sign);
+ zds = BDIGITS(z);
+
+#if SIZEOF_BDIGITS == SIZEOF_LONG
+ i = 1;
+ zds[0] = xds[0] | y;
+#else
+ {
+ BDIGIT_DBL num = y;
+
+ for (i=0; i<(int)(sizeof(y)/sizeof(BDIGIT)); i++) {
+ zds[i] = xds[i] | BIGLO(num);
+ num = BIGDN(num);
+ }
+ }
+#endif
+ while (i < xn) {
+ zds[i] = sign?xds[i]:(BDIGIT)(BIGRAD-1);
+ i++;
+ }
+ if (!RBIGNUM_SIGN(z)) get2comp(z);
+ return bignorm(z);
+}
+
/*
* call-seq:
* big | numeric => integer
@@ -2614,18 +2694,18 @@ rb_big_or(VALUE xx, VALUE yy)
x = xx;
y = bit_coerce(yy);
+
+ if (!RBIGNUM_SIGN(x)) {
+ x = rb_big_clone(x);
+ get2comp(x);
+ }
if (FIXNUM_P(y)) {
- y = rb_int2big(FIX2LONG(y));
+ return bigor_int(x, FIX2LONG(y));
}
-
if (!RBIGNUM_SIGN(y)) {
y = rb_big_clone(y);
get2comp(y);
}
- if (!RBIGNUM_SIGN(x)) {
- x = rb_big_clone(x);
- get2comp(x);
- }
if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
l1 = RBIGNUM_LEN(y);
l2 = RBIGNUM_LEN(x);
@@ -2650,10 +2730,44 @@ rb_big_or(VALUE xx, VALUE yy)
zds[i] = sign?ds2[i]:(BDIGIT)(BIGRAD-1);
}
if (!RBIGNUM_SIGN(z)) get2comp(z);
-
return bignorm(z);
}
+static VALUE
+bigxor_int(VALUE x, long y)
+{
+ VALUE z;
+ BDIGIT *xds, *zds;
+ long xn, zn;
+ long i;
+ char sign;
+
+ sign = (y >= 0) ? 1 : 0;
+ xds = BDIGITS(x);
+ zn = xn = RBIGNUM_LEN(x);
+ z = bignew(zn, !(RBIGNUM_SIGN(x) ^ sign));
+ zds = BDIGITS(z);
+
+#if SIZEOF_BDIGITS == SIZEOF_LONG
+ i = 1;
+ zds[0] = xds[0] ^ y;
+#else
+ {
+ BDIGIT_DBL num = y;
+
+ for (i=0; i<(int)(sizeof(y)/sizeof(BDIGIT)); i++) {
+ zds[i] = xds[i] ^ BIGLO(num);
+ num = BIGDN(num);
+ }
+ }
+#endif
+ while (i < xn) {
+ zds[i] = sign?xds[i]:~xds[i];
+ i++;
+ }
+ if (!RBIGNUM_SIGN(z)) get2comp(z);
+ return bignorm(z);
+}
/*
* call-seq:
* big ^ numeric => integer
@@ -2672,18 +2786,18 @@ rb_big_xor(VALUE xx, VALUE yy)
x = xx;
y = bit_coerce(yy);
+
+ if (!RBIGNUM_SIGN(x)) {
+ x = rb_big_clone(x);
+ get2comp(x);
+ }
if (FIXNUM_P(y)) {
- y = rb_int2big(FIX2LONG(y));
+ return bigxor_int(x, FIX2LONG(y));
}
-
if (!RBIGNUM_SIGN(y)) {
y = rb_big_clone(y);
get2comp(y);
}
- if (!RBIGNUM_SIGN(x)) {
- x = rb_big_clone(x);
- get2comp(x);
- }
if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
l1 = RBIGNUM_LEN(y);
l2 = RBIGNUM_LEN(x);