summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-06-27 13:54:02 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-06-27 13:54:02 +0000
commitcd6912a5952e719c643d319d7120659ddd3de1c8 (patch)
tree7d8a31c1a56b267e0192f9d7e5d9f5a460b8f8b3
parentbc47f294ee88630bad65a603225b9486ec1752eb (diff)
* bignum.c (get2comp): Use bary_2comp.
(abs2twocomp_bang): New function. (abs2twocomp): New function. (twocomp2abs_bang): New function. (rb_big_and): Use abs2twocomp and twocomp2abs_bang. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41680 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog8
-rw-r--r--bignum.c110
2 files changed, 77 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog
index 4e63f7036b..658b0a9bb9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Thu Jun 27 22:52:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (get2comp): Use bary_2comp.
+ (abs2twocomp_bang): New function.
+ (abs2twocomp): New function.
+ (twocomp2abs_bang): New function.
+ (rb_big_and): Use abs2twocomp and twocomp2abs_bang.
+
Thu Jun 27 20:03:13 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
* ext/openssl/lib/openssl/ssl.rb (verify_certificate_identity): fix
diff --git a/bignum.c b/bignum.c
index 015eae924c..e2e172e0fc 100644
--- a/bignum.c
+++ b/bignum.c
@@ -289,17 +289,8 @@ get2comp(VALUE x)
{
long i = RBIGNUM_LEN(x);
BDIGIT *ds = BDIGITS(x);
- BDIGIT_DBL num;
- if (!i) return;
- while (i--) ds[i] = BIGLO(~ds[i]);
- i = 0; num = 1;
- do {
- num += ds[i];
- ds[i++] = BIGLO(num);
- num = BIGDN(num);
- } while (i < RBIGNUM_LEN(x));
- if (num != 0) {
+ if (bary_2comp(ds, i)) {
rb_big_resize(x, RBIGNUM_LEN(x)+1);
ds = BDIGITS(x);
ds[RBIGNUM_LEN(x)-1] = 1;
@@ -312,6 +303,50 @@ rb_big_2comp(VALUE x) /* get 2's complement */
get2comp(x);
}
+static BDIGIT
+abs2twocomp_bang(VALUE x)
+{
+ long numbdigits = RBIGNUM_LEN(x);
+ long n;
+ BDIGIT *ds = BDIGITS(x);
+ BDIGIT hibits;
+
+ n = numbdigits;
+
+ while (0 < n && ds[n-1] == 0)
+ n--;
+
+ if (n == 0 || RBIGNUM_POSITIVE_P(x))
+ hibits = 0;
+ else {
+ hibits = BDIGMAX;
+ bary_2comp(ds, numbdigits);
+ }
+
+ return hibits;
+}
+
+static BDIGIT
+abs2twocomp(VALUE *xp)
+{
+ VALUE x = *xp;
+ BDIGIT hibits = 0;
+ if (RBIGNUM_NEGATIVE_P(x)) {
+ *xp = x = rb_big_clone(x);
+ hibits = abs2twocomp_bang(x);
+ }
+ return hibits;
+}
+
+static void
+twocomp2abs_bang(VALUE x, int hibits)
+{
+ RBIGNUM_SET_SIGN(x, !hibits);
+ if (hibits) {
+ get2comp(x);
+ }
+}
+
static inline VALUE
bigtrunc(VALUE x)
{
@@ -4691,55 +4726,48 @@ bigand_int(VALUE x, long y)
*/
VALUE
-rb_big_and(VALUE xx, VALUE yy)
+rb_big_and(VALUE x, VALUE y)
{
- volatile VALUE x, y, z;
+ VALUE z;
BDIGIT *ds1, *ds2, *zds;
long i, l1, l2;
- char sign;
+ BDIGIT hibitsx, hibitsy;
+ BDIGIT hibits1, hibits2;
+ VALUE tmpv;
+ BDIGIT tmph;
- if (!FIXNUM_P(yy) && !RB_TYPE_P(yy, T_BIGNUM)) {
- return rb_num_coerce_bit(xx, yy, '&');
+ if (!FIXNUM_P(y) && !RB_TYPE_P(y, T_BIGNUM)) {
+ return rb_num_coerce_bit(x, y, '&');
}
- x = xx;
- y = yy;
-
- if (!RBIGNUM_SIGN(x)) {
- x = rb_big_clone(x);
- get2comp(x);
- }
+ hibitsx = abs2twocomp(&x);
if (FIXNUM_P(y)) {
return bigand_int(x, FIX2LONG(y));
}
- if (!RBIGNUM_SIGN(y)) {
- y = rb_big_clone(y);
- get2comp(y);
- }
+ hibitsy = abs2twocomp(&y);
if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
- l1 = RBIGNUM_LEN(y);
- l2 = RBIGNUM_LEN(x);
- ds1 = BDIGITS(y);
- ds2 = BDIGITS(x);
- sign = RBIGNUM_SIGN(y);
- }
- else {
- l1 = RBIGNUM_LEN(x);
- l2 = RBIGNUM_LEN(y);
- ds1 = BDIGITS(x);
- ds2 = BDIGITS(y);
- sign = RBIGNUM_SIGN(x);
+ tmpv = x; x = y; y = tmpv;
+ tmph = hibitsx; hibitsx = hibitsy; hibitsy = tmph;
}
- z = bignew(l2, RBIGNUM_SIGN(x) || RBIGNUM_SIGN(y));
+ l1 = RBIGNUM_LEN(x);
+ l2 = RBIGNUM_LEN(y);
+ ds1 = BDIGITS(x);
+ ds2 = BDIGITS(y);
+ hibits1 = hibitsx;
+ hibits2 = hibitsy;
+
+ z = bignew(l2, 0);
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];
+ zds[i] = hibits1 & ds2[i];
}
- if (!RBIGNUM_SIGN(z)) get2comp(z);
+ twocomp2abs_bang(z, hibits1 && hibits2);
+ RB_GC_GUARD(x);
+ RB_GC_GUARD(y);
return bignorm(z);
}