aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-06-26 03:16:12 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-06-26 03:16:12 +0000
commit9be51267b54f923e9e95824984416eca9b95dd6c (patch)
treeefd6bb171fcdc6310fd7832c537f20ebf4f29ada
parent3a8100835485c64f97e10a3cd1624a1b33145326 (diff)
downloadruby-9be51267b54f923e9e95824984416eca9b95dd6c.tar.gz
* bignum.c (bigand_int): Consider negative values.
(bigor_int): The allocated bignum should have enough size to store long. This fixes (bignum fits in a BDIGIT) | (fixnum bigger than BDIGIT) on platforms which SIZEOF_BDIGITS < SIZEOF_LONG, such as LP64 with 32bit BDIGIT (no int128). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41639 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog9
-rw-r--r--bignum.c64
-rw-r--r--test/ruby/test_bignum.rb7
-rw-r--r--test/ruby/test_integer_comb.rb2
4 files changed, 70 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 9ac327b9c5..84948c2957 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Wed Jun 26 12:13:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigand_int): Consider negative values.
+ (bigor_int): The allocated bignum should have enough size
+ to store long.
+ This fixes (bignum fits in a BDIGIT) | (fixnum bigger than BDIGIT)
+ on platforms which SIZEOF_BDIGITS < SIZEOF_LONG,
+ such as LP64 with 32bit BDIGIT (no int128).
+
Wed Jun 26 12:08:51 2013 Tanaka Akira <akr@fsij.org>
* test/socket/test_udp.rb: Close sockets explicitly.
diff --git a/bignum.c b/bignum.c
index 7e36ccbb15..ce0706631a 100644
--- a/bignum.c
+++ b/bignum.c
@@ -4643,6 +4643,10 @@ bigand_int(VALUE x, long y)
return LONG2NUM(y);
}
#endif
+#if SIZEOF_BDIGITS < SIZEOF_LONG
+ if (RBIGNUM_NEGATIVE_P(x) && zn < bdigit_roomof(SIZEOF_LONG))
+ zn = bdigit_roomof(SIZEOF_LONG);
+#endif
z = bignew(zn, RBIGNUM_SIGN(x) || sign);
zds = BDIGITS(z);
@@ -4656,10 +4660,18 @@ bigand_int(VALUE x, long y)
zds[i] = xds[i] & BIGLO(y);
y = BIGDN(y);
}
+ for (; i < zn; i++) {
+ if (y == 0 || y == -1) break;
+ zds[i] = RBIGNUM_NEGATIVE_P(x) ? BIGLO(y) : 0;
+ y = BIGDN(y);
+ }
+
#endif
- while (i < xn) {
+ for (;i < xn; i++) {
zds[i] = sign?0:xds[i];
- i++;
+ }
+ for (;i < zn; i++) {
+ zds[i] = (!sign && RBIGNUM_NEGATIVE_P(x)) ? BDIGMAX : 0;
}
if (!RBIGNUM_SIGN(z)) get2comp(z);
return bignorm(z);
@@ -4737,26 +4749,54 @@ bigor_int(VALUE x, long y)
sign = (y >= 0);
xds = BDIGITS(x);
zn = xn = RBIGNUM_LEN(x);
+#if SIZEOF_BDIGITS < SIZEOF_LONG
+ if (zn < bdigit_roomof(SIZEOF_LONG))
+ zn = bdigit_roomof(SIZEOF_LONG);
+#endif
z = bignew(zn, RBIGNUM_SIGN(x) && sign);
zds = BDIGITS(z);
#if SIZEOF_BDIGITS >= SIZEOF_LONG
i = 1;
zds[0] = xds[0] | y;
+ if (i < zn)
+ goto y_is_fixed_point;
+ goto finish;
#else
- {
- long num = y;
-
- for (i=0; i<bdigit_roomof(SIZEOF_LONG); i++) {
- zds[i] = xds[i] | BIGLO(num);
- num = BIGDN(num);
- }
+ for (i=0; i < xn; i++) {
+ if (y == 0 || y == -1) goto y_is_fixed_point;
+ zds[i] = xds[i] | BIGLO(y);
+ y = BIGDN(y);
}
+ if (RBIGNUM_NEGATIVE_P(x))
+ goto fill_hibits;
+ for (; i < zn; i++) {
+ if (y == 0 || y == -1) goto y_is_fixed_point;
+ zds[i] = BIGLO(y);
+ y = BIGDN(y);
+ }
+ goto finish;
#endif
- while (i < xn) {
- zds[i] = sign?xds[i]:BDIGMAX;
- i++;
+
+ y_is_fixed_point:
+ if (!sign)
+ goto fill_hibits;
+ for (; i < xn; i++) {
+ zds[i] = xds[i];
+ }
+ if (RBIGNUM_NEGATIVE_P(x))
+ goto fill_hibits;
+ for (; i < zn; i++) {
+ zds[i] = 0;
}
+ goto finish;
+
+ fill_hibits:
+ for (; i < zn; i++) {
+ zds[i] = BDIGMAX;
+ }
+
+ finish:
if (!RBIGNUM_SIGN(z)) get2comp(z);
return bignorm(z);
}
diff --git a/test/ruby/test_bignum.rb b/test/ruby/test_bignum.rb
index 9f709daa8a..f0d76c83bf 100644
--- a/test/ruby/test_bignum.rb
+++ b/test/ruby/test_bignum.rb
@@ -123,6 +123,12 @@ class TestBignum < Test::Unit::TestCase
T1024 = b.coerce(2**1024).first
T1024P = b.coerce(T1024 - 1).first
+ f = b
+ while Bignum === f-1
+ f = f >> 1
+ end
+ FIXNUM_MAX = f-1
+
def test_prepare
assert_instance_of(Bignum, T_ZERO)
assert_instance_of(Bignum, T_ONE)
@@ -454,6 +460,7 @@ class TestBignum < Test::Unit::TestCase
assert_equal(T32 + T31, T32 | T31)
assert_equal(-T31, (-T32) | (-T31))
assert_equal(T64 + T32, T32 | T64)
+ assert_equal(FIXNUM_MAX, T_ZERO | FIXNUM_MAX)
end
def test_xor
diff --git a/test/ruby/test_integer_comb.rb b/test/ruby/test_integer_comb.rb
index c057deb36f..3f5a0aa0a7 100644
--- a/test/ruby/test_integer_comb.rb
+++ b/test/ruby/test_integer_comb.rb
@@ -106,6 +106,8 @@ class TestIntegerComb < Test::Unit::TestCase
]
#VS.map! {|v| 0x4000000000000000.coerce(v)[0] }
+ #VS.concat VS.find_all {|v| Fixnum === v }.map {|v| 0x4000000000000000.coerce(v)[0] }
+ #VS.sort! {|a, b| a.abs <=> b.abs }
min = -1
min *= 2 while min.class == Fixnum