Author: stian
Branch: bigint-with-int
Changeset: r65991:9fbd5a1f8450
Date: 2013-08-05 05:50 +0200
http://bitbucket.org/pypy/pypy/changeset/9fbd5a1f8450/
Log: Some fixes, some debug code.
diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -42,6 +42,7 @@
LONG_TYPE = rffi.LONGLONG
MASK = int((1 << SHIFT) - 1)
+MIN_VALUE = int((-1 << SHIFT))
FLOAT_MULTIPLIER = float(1 << SHIFT)
# Debugging digit array access.
@@ -615,10 +616,18 @@
def int_add(self, other):
if other == 0:
return self
- if self.sign == 0:
+ elif self.sign == 0:
return rbigint.fromint(other)
+ elif other == MIN_VALUE:
+ # Fallback to long.
+ return self.add(rbigint.fromint(other))
+
+ digit = UDIGIT_TYPE(abs(other))
+
+ assert digit > 0 # Required.
+
if (self.sign > 0 and other > 0) or (self.sign < 0 and other < 0):
- result = _x_int_add(self, abs(other))
+ result = _x_int_add(self, digit)
else:
# XXX: Improve.
result = _x_sub(rbigint.fromint(other), self)
@@ -643,12 +652,17 @@
def int_sub(self, other):
if other == 0:
return self
- if self.sign == 0:
+ elif self.sign == 0:
return rbigint.fromint(-1 * other)
+
+ if other == MIN_VALUE:
+ # Fallback to long.
+ return self.sub(rbigint.fromint(other))
+
if (self.sign > 0 and other > 0) or (self.sign < 0 and other < 0):
- result = _x_int_sub(self, abs(other))
+ result = _x_int_sub(self, other)
else:
- result = _x_int_add(self, abs(other))
+ result = _x_int_add(self, UDIGIT_TYPE(abs(other)))
result.sign *= self.sign
return result
@@ -700,6 +714,11 @@
@jit.elidable
def int_mul(self, b):
""" Mul with int. """
+ if b == MIN_VALUE:
+ # Fallback to long.
+ return self.mul(rbigint.fromint(b))
+
+ digit = _widen_digit(b)
asize = self.numdigits()
if self.sign == 0 or b == 0:
@@ -711,7 +730,7 @@
elif self._digits[0] == ONEDIGIT:
return rbigint.fromint(self.sign * b)
- res = self.widedigit(0) * abs(b)
+ res = self.widedigit(0) * digit
carry = res >> SHIFT
if carry:
return rbigint([_store_digit(res & MASK),
_store_digit(carry)], self.sign * (-1 if b < 0 else 1), 2)
@@ -719,7 +738,7 @@
return rbigint([_store_digit(res & MASK)], self.sign * (-1 if
b < 0 else 1), 1)
else:
- result = _x_int_mul(self, abs(b))
+ result = _x_int_mul(self, digit)
result.sign = self.sign * (-1 if b < 0 else 1)
return result
@@ -741,9 +760,9 @@
digit = other.digit(0)
if digit == 1:
return self
- elif digit and digit & (digit - 1) == 0:
+ """elif digit and digit & (digit - 1) == 0:
return self.rshift(ptwotable[digit])
-
+ """
div, mod = _divrem(self, other)
if mod.sign * other.sign == -1:
if div.sign == 0:
@@ -754,17 +773,21 @@
@jit.elidable
def int_floordiv(self, other):
-
if other == 0:
raise ZeroDivisionError("long division or modulo by zero")
-
+ elif other == MIN_VALUE:
+ # Fallback to long.
+ return self.floordiv(rbigint.fromint(other))
+
digit = abs(other)
+ assert digit > 0
+
if self.sign == 1 and other > 0:
if digit == 1:
return self
- elif digit and digit & (digit - 1) == 0:
+ """elif digit & (digit - 1) == 0:
return self.rshift(ptwotable[digit])
-
+ """
div, mod = _divrem1(self, digit)
if mod != 0 and self.sign * (-1 if other < 0 else 1) == -1:
@@ -823,6 +846,9 @@
def int_mod(self, other):
if self.sign == 0:
return NULLRBIGINT
+ elif other == MIN_VALUE:
+ # Fallback to long.
+ self.mod(rbigint.fromint(other))
digit = abs(other)
@@ -892,13 +918,16 @@
if w == 0:
raise ZeroDivisionError("long division or modulo by zero")
+ digit = abs(w)
wsign = (-1 if w < 0 else 1)
- if v.sign != wsign:
+ if digit >= MASK or not (digit > 0) or v.sign != wsign:
# Divrem1 doesn't deal with the sign difference. Instead of having
yet another copy,
# Just fallback.
return v.divmod(rbigint.fromint(w))
- div, mod = _divrem1(v, abs(w))
+ assert digit > 0
+
+ div, mod = _divrem1(v, digit)
mod = rbigint.fromint(mod)
mod.sign = wsign
@@ -1353,14 +1382,11 @@
def _x_int_add(a, b):
""" Add the absolute values of one bigint and one int. """
size_a = a.numdigits()
-
z = rbigint([NULLDIGIT] * (size_a + 1), 1)
- i = UDIGIT_TYPE(0)
-
carry = a.udigit(0) + b
z.setdigit(0, carry)
carry >>= SHIFT
- i += 1
+ i = UDIGIT_TYPE(1)
while i < size_a:
carry += a.udigit(i)
z.setdigit(i, carry)
@@ -1412,6 +1438,9 @@
#borrow &= 1
i += 1
+ if borrow != 0:
+ print a.str(), " minus ", b.str()
+
assert borrow == 0
z._normalize()
return z
@@ -1420,23 +1449,22 @@
""" Subtract the absolute values of one rbigint and one integer. """
size_a = a.numdigits()
+
sign = 1
-
if size_a == 1:
- # Find highest digit where a and b differ:
- if a.digit(0) == b:
+ adigit = a.digit(0)
+ if adigit == b:
return NULLRBIGINT
- elif a.digit(0) < b:
- sign = -1
- b *= -1
- size_a = size_b = 1
+ elif adigit > b:
+ return rbigint.fromint(adigit - b)
z = rbigint([NULLDIGIT] * size_a, sign, size_a)
borrow = UDIGIT_TYPE(0)
i = _load_unsigned_digit(1)
# The following assumes unsigned arithmetic
# works modulo 2**N for some N>SHIFT.
- borrow = a.udigit(0) - b
+
+ borrow = a.udigit(0) - UDIGIT_TYPE(abs(b))
z.setdigit(0, borrow)
borrow >>= SHIFT
while i < size_a:
@@ -1446,6 +1474,9 @@
#borrow &= 1
i += 1
+ if borrow > 0:
+ print "BORROW IS BAD"
+
assert borrow == 0
z._normalize()
return z
@@ -1505,13 +1536,13 @@
z._normalize()
return z
- elif digit:
+ """elif digit:
if digit & (digit - 1) == 0:
return b.lqshift(ptwotable[digit])
# Even if it's not power of two it can still be useful.
return _muladd1(b, digit)
-
+ """
z = rbigint([NULLDIGIT] * (size_a + size_b), 1)
# gradeschool long mult
i = UDIGIT_TYPE(0)
@@ -1786,6 +1817,9 @@
and the remainder as a tuple.
The sign of a is ignored; n should not be zero.
"""
+ if not (n > 0 and n <= MASK):
+ print "Trying to divide %s by %d" % (a.str(), n)
+
assert n > 0 and n <= MASK
size = a.numdigits()
@@ -1997,6 +2031,10 @@
if b.sign == 0:
raise ZeroDivisionError("long division or modulo by zero")
+ # XXX: Temp
+ if b.sign != 0 and b.numdigits() == 1 and b.digit(0) == 0:
+ print "VERY BAD!"
+
if (size_a < size_b or
(size_a == size_b and
a.digit(abs(size_a-1)) < b.digit(abs(size_b-1)))):
@@ -2540,6 +2578,13 @@
def _int_bitwise(a, op, b): # '&', '|', '^'
""" Bitwise and/or/xor operations with ints. """
+ digit = abs(b)
+ if digit > MASK or not (digit >= 0):
+ # Fallback to long.
+ return _bitwise(a, op, rbigint.fromint(b))
+
+ assert digit >= 0
+
if a.sign < 0:
a = a.invert()
maska = MASK
diff --git a/rpython/rlib/test/test_rbigint.py
b/rpython/rlib/test/test_rbigint.py
--- a/rpython/rlib/test/test_rbigint.py
+++ b/rpython/rlib/test/test_rbigint.py
@@ -41,6 +41,30 @@
r2 = r1.neg()
assert r2.str() == str(-n)
+ def test_int_long_catch_div(self):
+ # Basically abs(int) > MASK
+ l = 2**128
+ r1 = rbigint.fromlong(l)
+ assert r1.int_floordiv(-MASK-1).tolong() == (l // (-MASK-1))
+
+ def test_int_long_catch_mul(self):
+ # Basically abs(int) > MASK
+ l = 2**128
+ r1 = rbigint.fromlong(l)
+ assert r1.int_mul(-MASK-1).tolong() == (l * (-MASK-1))
+
+ def test_int_long_catch_add(self):
+ # Basically abs(int) > MASK
+ l = 2**128
+ r1 = rbigint.fromlong(-l)
+ assert r1.int_add(-MASK-1).tolong() == (-l + (-MASK-1))
+
+ def test_int_long_catch_sub(self):
+ # Basically abs(int) > MASK
+ l = 2**128
+ r1 = rbigint.fromlong(-l)
+ assert r1.int_sub(-MASK-1).tolong() == (-l - (-MASK-1))
+
def test_floordiv(self):
for op1 in [-12, -2, -1, 1, 2, 50]:
for op2 in [-4, -2, -1, 1, 2, 8]:
@@ -246,7 +270,7 @@
assert rbigint._from_numberstring_parser(parser).tolong() == 1231231241
def test_add(self):
- x = 123456789123456789000000L
+ x = 123456789123456789000000000000000000L
y = 123858582373821923936744221L
for i in [-1, 1]:
for j in [-1, 1]:
@@ -256,8 +280,8 @@
assert result.tolong() == x * i + y * j
def test_int_add(self):
- x = 123456789123456789000000L
- y = 1238
+ x = 123456789123456789000000000000000000L
+ y = MASK-2
for i in [-1, 1]:
for j in [-1, 1]:
f1 = rbigint.fromlong(x * i)
@@ -278,7 +302,7 @@
def test_int_sub(self):
x = 12378959520302182384345L
- y = 8896
+ y = MASK
for i in [-1, 1]:
for j in [-1, 1]:
f1 = rbigint.fromlong(x * i)
@@ -303,7 +327,7 @@
def test_int_mul(self):
x = -1238585838347L
- y = 585839
+ y = MASK
f1 = rbigint.fromlong(x)
result = f1.int_mul(y)
assert result.tolong() == x * y
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit