[pypy-svn] r14360 - pypy/dist/pypy/objspace/std

tismer at codespeak.net tismer at codespeak.net
Wed Jul 6 20:45:19 CEST 2005


Author: tismer
Date: Wed Jul  6 20:45:18 2005
New Revision: 14360

Modified:
   pypy/dist/pypy/objspace/std/longobject.py
Log:
things seem to work quite nicely.
allmost everything was generalized.

still tracking down the last bug with special cases.


Modified: pypy/dist/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longobject.py	(original)
+++ pypy/dist/pypy/objspace/std/longobject.py	Wed Jul  6 20:45:18 2005
@@ -3,29 +3,39 @@
 from pypy.objspace.std.intobject import W_IntObject
 from pypy.objspace.std.floatobject import W_FloatObject
 from pypy.objspace.std.noneobject import W_NoneObject
-from pypy.rpython.rarithmetic import intmask, r_uint, LONG_MASK
+from pypy.rpython.rarithmetic import intmask, r_uint, r_ushort, r_ulong
 from pypy.rpython.rarithmetic import LONG_BIT
 
 import math
 
+# for now, we use r_uint as a digit.
+# we may later switch to r_ushort, when it is supported by rtyper etc.
+
+Digit = r_uint # works: r_ushort
+Twodigits = r_uint
+Stwodigits = int
+
 # the following describe a plain digit
-SHIFT = int(LONG_BIT // 2) #- 1
+SHIFT = (Twodigits.BITS // 2) - 1
 MASK = int((1 << SHIFT) - 1)
 
+# find the correct type for carry/borrow
+if Digit.BITS - SHIFT > 0:
+    Carryadd = Digit
+else:
+    Carryadd = Twodigits
+Carrymul = Twodigits
+
 # masks for normal signed integer
 SIGN_BIT = LONG_BIT-1
 SIGN_MASK = r_uint(1) << SIGN_BIT
 NONSIGN_MASK = ~SIGN_MASK
 
-# masks for half-word access
-SHORT_BIT = LONG_BIT // 2
-SHORT_MASK = int((1 << SHORT_BIT) - 1)
-
 # XXX some operations below return one of their input arguments
 #     without checking that it's really of type long (and not a subclass).
 
 class W_LongObject(W_Object):
-    """This is a reimplementation of longs using a list of r_uints."""
+    """This is a reimplementation of longs using a list of digits."""
     # All functions that still rely on the underlying Python's longs are marked
     # with YYYYYY
     from pypy.objspace.std.longtype import long_typedef as typedef
@@ -41,7 +51,7 @@
     def longval(self): #YYYYYY
         l = 0
         for d in self.digits[::-1]:
-            l = l << LONG_BIT
+            l = l << SHIFT
             l += long(d)
         return l * self.sign
 
@@ -51,7 +61,7 @@
     def _normalize(self):
         if len(self.digits) == 0:
             self.sign = 0
-            self.digits = [r_uint(0)]
+            self.digits = [Digit(0)]
             return
         i = len(self.digits) - 1
         while i != 0 and self.digits[i] == 0:
@@ -60,41 +70,17 @@
         if len(self.digits) == 1 and self.digits[0] == 0:
             self.sign = 0
 
-    def _getshort(self, index):
-        a = self.digits[index // 2]
-        if index % 2 == 0:
-            return a & SHORT_MASK
-        else:
-            return a >> SHORT_BIT
-
-    def _setshort(self, index, short):
-        a = self.digits[index // 2]
-        assert isinstance(short, r_uint)
-        # note that this is possibly one bit more than a digit
-        assert short & SHORT_MASK == short
-        if index % 2 == 0:
-            self.digits[index // 2] = ((a >> SHORT_BIT) << SHORT_BIT) + short
-        else:
-            self.digits[index // 2] = (a & SHORT_MASK) + (short << SHORT_BIT)
-
 
 registerimplementation(W_LongObject)
 
 # bool-to-long
 def delegate_Bool2Long(w_bool):
-    return W_LongObject(w_bool.space, [r_uint(w_bool.boolval)],
+    return W_LongObject(w_bool.space, [Digit(w_bool.boolval)],
                         int(w_bool.boolval))
 
 # int-to-long delegation
 def delegate_Int2Long(w_intobj):
-    if w_intobj.intval < 0:
-        sign = -1
-    elif w_intobj.intval > 0:
-        sign = 1
-    else:
-        sign = 0
-    digits = [r_uint(abs(w_intobj.intval))]
-    return W_LongObject(w_intobj.space, digits, sign)
+    return long__Int(w_intobj.space, w_intobj)
 
 # long-to-float delegation
 def delegate_Long2Float(w_longobj):
@@ -118,20 +104,37 @@
 def long__Int(space, w_intobj):
     if w_intobj.intval < 0:
         sign = -1
+        ival = -w_intobj.intval
     elif w_intobj.intval > 0:
         sign = 1
+        ival = w_intobj.intval
     else:
-        sign = 0
-    return W_LongObject(space, [r_uint(abs(w_intobj.intval))], sign)
+        return W_LongObject(space, [Digit(0)], 0)
+    # Count the number of Python digits.
+    # We used to pick 5 ("big enough for anything"), but that's a
+    # waste of time and space given that 5*15 = 75 bits are rarely
+    # needed.
+    t = r_uint(ival)
+    ndigits = 0
+    while t:
+        ndigits += 1
+        t >>= SHIFT
+    v = W_LongObject(space, [Digit(0)] * ndigits, sign)
+    t = r_uint(ival)
+    p = 0
+    while t:
+        v.digits[p] = Digit(t & MASK)
+        t >>= SHIFT
+        p += 1
+    return v
 
 def int__Long(space, w_value):
-    if len(w_value.digits) == 1:
-        if w_value.digits[0] & SIGN_MASK == 0:
-            return space.newint(int(w_value.digits[0]) * w_value.sign)
-        elif w_value.sign == -1 and w_value.digits[0] & NONSIGN_MASK == 0:
-            return space.newint(intmask(w_value.digits[0]))
-    #subtypes of long are converted to long!
-    return long__Long(space, w_value)
+    try:
+        x = _AsLong(w_value)
+    except OverflowError:
+        return long__Long(space, w_value)
+    else:
+        return space.newint(x)
 
 def float__Long(space, w_longobj):
     try:
@@ -144,23 +147,22 @@
     return _FromDouble(space, w_floatobj.floatval)
 
 def int_w__Long(space, w_value):
-    if len(w_value.digits) == 1:
-        if  w_value.digits[0] & SIGN_MASK == 0:
-            return int(w_value.digits[0]) * w_value.sign
-        elif w_value.sign == -1 and w_value.digits[0] & NONSIGN_MASK == 0:
-            return intmask(w_value.digits[0])
-    raise OperationError(space.w_OverflowError,
-                         space.wrap("long int too large to convert to int"))
+    try:
+        return _AsLong(w_value)
+    except OverflowError:
+        raise OperationError(space.w_OverflowError, space.wrap(
+            "long int too large to convert to int"))
+
 
 def uint_w__Long(space, w_value):
     if w_value.sign == -1:
         raise OperationError(space.w_ValueError, space.wrap(
             "cannot convert negative integer to unsigned int"))
     x = r_uint(0)
-    i = len(w_value.digits) * 2 - 1
+    i = len(w_value.digits) - 1
     while i >= 0:
         prev = x
-        x = (x << SHIFT) + w_value._getshort(i)
+        x = (x << SHIFT) + w_value.digits[i]
         if (x >> SHIFT) != prev:
             raise OperationError(space.w_OverflowError, space.wrap(
                 "long int too large to convert to unsigned int"))
@@ -298,7 +300,7 @@
         if lz.sign == 0:
             raise OperationError(space.w_ValueError,
                                     space.wrap("pow() 3rd argument cannot be 0"))
-    result = W_LongObject(space, [r_uint(1)], 1)
+    result = W_LongObject(space, [Digit(1)], 1)
     if lw.sign == 0:
         if lz is not None:
             result = mod__Long_Long(space, result, lz)
@@ -311,9 +313,9 @@
     #Treat the most significant digit specially to reduce multiplications
     while i < len(lw.digits) - 1:
         j = 0
-        m = r_uint(1)
+        m = Digit(1)
         di = lw.digits[i]
-        while j < LONG_BIT:
+        while j < SHIFT:
             if di & m:
                 result = mul__Long_Long(space, result, temp)
             temp = mul__Long_Long(space, temp, temp)
@@ -323,9 +325,9 @@
             m = m << 1
             j += 1
         i += 1
-    m = r_uint(1) << (LONG_BIT - 1)
-    highest_set_bit = LONG_BIT
-    j = LONG_BIT - 1
+    m = Digit(1) << (SHIFT - 1)
+    highest_set_bit = SHIFT
+    j = SHIFT - 1
     di = lw.digits[i]
     while j >= 0:
         if di & m:
@@ -333,9 +335,9 @@
             break
         m = m >> 1
         j -= 1
-    assert highest_set_bit != LONG_BIT, "long not normalized"
+    assert highest_set_bit != SHIFT, "long not normalized"
     j = 0
-    m = r_uint(1)
+    m = Digit(1)
     while j <= highest_set_bit:
         if di & m:
             result = mul__Long_Long(space, result, temp)
@@ -369,7 +371,7 @@
     return space.newbool(w_long.sign != 0)
 
 def invert__Long(space, w_long): #Implement ~x as -(x + 1)
-    w_lpp = add__Long_Long(space, w_long, W_LongObject(space, [r_uint(1)], 1))
+    w_lpp = add__Long_Long(space, w_long, W_LongObject(space, [Digit(1)], 1))
     return neg__Long(space, w_lpp)
 
 def lshift__Long_Long(space, w_long1, w_long2):
@@ -379,35 +381,39 @@
     elif w_long2.sign == 0:
         return w_long1
     try:
-        b = int_w__Long(space, w_long2)
+        shiftby = int_w__Long(space, w_long2)
     except OverflowError:   # b too big
         raise OperationError(space.w_OverflowError,
                              space.wrap("shift count too large"))
-    wordshift = b // LONG_BIT
-    remshift = r_uint(b) % LONG_BIT
-    oldsize = len(w_long1.digits)
+
+    a = w_long1
+    # wordshift, remshift = divmod(shiftby, SHIFT)
+    wordshift = shiftby // SHIFT
+    remshift  = shiftby - wordshift * SHIFT
+
+    oldsize = len(a.digits)
     newsize = oldsize + wordshift
-    if remshift != 0:
+    if remshift:
         newsize += 1
-    w_result = W_LongObject(space, [r_uint(0)] * newsize, w_long1.sign)
-    rightshift = LONG_BIT - remshift
-    LOWER_MASK = (r_uint(1) << r_uint(rightshift)) - 1
-    UPPER_MASK = ~LOWER_MASK
-    accum = r_uint(0)
+    z = W_LongObject(space, [Digit(0)] * newsize, a.sign)
+    # not sure if we will initialize things in the future?
+    for i in range(wordshift):
+        z.digits[i] = 0
+    accum = Twodigits(0)
     i = wordshift
     j = 0
     while j < oldsize:
-        digit = w_long1.digits[j]
-        w_result.digits[i] = (accum | (digit << remshift))
-        accum = (digit & UPPER_MASK) >> rightshift
+        accum |= Twodigits(a.digits[j]) << remshift
+        z.digits[i] = Digit(accum & MASK)
+        accum >>= SHIFT
         i += 1
         j += 1
     if remshift:
-        w_result.digits[i] = accum
+        z.digits[newsize-1] = Digit(accum)
     else:
         assert not accum
-    w_result._normalize()
-    return w_result
+    z._normalize()
+    return z
 
 def rshift__Long_Long(space, w_long1, w_long2):
     if w_long2.sign < 0:
@@ -420,31 +426,32 @@
         w_a2 = rshift__Long_Long(space, w_a1, w_long2)
         return invert__Long(space, w_a2)
     try:
-        b = int_w__Long(space, w_long2)
+        shiftby = int_w__Long(space, w_long2)
     except OverflowError:   # b too big # XXX maybe just return 0L instead?
         raise OperationError(space.w_OverflowError,
                              space.wrap("shift count too large"))
-    wordshift = b // LONG_BIT
-    remshift = r_uint(b) % LONG_BIT
-    oldsize = len(w_long1.digits)
-    newsize = oldsize - wordshift
+
+    a = w_long1
+    wordshift = shiftby // SHIFT
+    newsize = len(a.digits) - wordshift
     if newsize <= 0:
-        return W_LongObject(space, [r_uint(0)], 0)
-    w_result = W_LongObject(space, [r_uint(0)] * newsize, 1)
-    leftshift = LONG_BIT - remshift
-    LOWER_MASK = (r_uint(1) << r_uint(remshift)) - 1
-    UPPER_MASK = ~LOWER_MASK
-    accum = r_uint(0)
-    i = newsize - 1
-    j = oldsize - 1
-    while i >= 0:
-        digit = w_long1.digits[j]
-        w_result.digits[i] = (accum | (digit >> remshift))
-        accum = (digit & LOWER_MASK) << leftshift
-        i -= 1
-        j -= 1
-    w_result._normalize()
-    return w_result
+        return W_LongObject(space, [Digit(0)], 0)
+
+    loshift = shiftby % SHIFT
+    hishift = SHIFT - loshift
+    lomask = (Digit(1) << hishift) - 1
+    himask = MASK ^ lomask
+    z = W_LongObject(space, [Digit(0)] * newsize, a.sign)
+    i = 0
+    j = wordshift
+    while i < newsize:
+        z.digits[i] = (a.digits[j] >> loshift) & lomask
+        if i+1 < newsize:
+            z.digits[i] |= (a.digits[j+1] << hishift) & himask
+        i += 1
+        j += 1
+    z._normalize()
+    return z
 
 def and__Long_Long(space, w_long1, w_long2):
     return _bitwise(w_long1, '&', w_long2)
@@ -517,45 +524,45 @@
     digits = []
     i = 0
     while l:
-        digits.append(r_uint(l & LONG_MASK))
-        l = l >> LONG_BIT
+        digits.append(Digit(l & MASK))
+        l = l >> SHIFT
     if sign == 0:
-        digits = [r_uint(0)]
+        digits = [Digit(0)]
     return digits, sign
 
 
 def _x_add(a, b):
     """ Add the absolute values of two long integers. """
-    size_a = len(a.digits) * 2
-    size_b = len(b.digits) * 2
+    size_a = len(a.digits)
+    size_b = len(b.digits)
 
     # Ensure a is the larger of the two:
     if size_a < size_b:
         a, b = b, a
         size_a, size_b = size_b, size_a
-    z = W_LongObject(a.space, [r_uint(0)] * (len(a.digits) + 1), 1)
+    z = W_LongObject(a.space, [Digit(0)] * (len(a.digits) + 1), 1)
     i = 0
-    carry = r_uint(0)
+    carry = Carryadd(0)
     while i < size_b:
-        carry += a._getshort(i) + b._getshort(i)
-        z._setshort(i, carry & MASK)
+        carry += a.digits[i] + b.digits[i]
+        z.digits[i] = carry & MASK
         carry >>= SHIFT
         i += 1
     while i < size_a:
-        carry += a._getshort(i)
-        z._setshort(i, carry & MASK)
+        carry += a.digits[i]
+        z.digits[i] = carry & MASK
         carry >>= SHIFT
         i += 1
-    z._setshort(i, carry)
+    z.digits[i] = carry
     z._normalize()
     return z
 
 def _x_sub(a, b):
     """ Subtract the absolute values of two integers. """
-    size_a = len(a.digits) * 2
-    size_b = len(b.digits) * 2
+    size_a = len(a.digits)
+    size_b = len(b.digits)
     sign = 1
-    borrow = 0
+    borrow = Digit(0)
 
     # Ensure a is the larger of the two:
     if size_a < size_b:
@@ -565,28 +572,27 @@
     elif size_a == size_b:
         # Find highest digit where a and b differ:
         i = size_a - 1
-        while i >= 0 and a._getshort(i) == b._getshort(i):
+        while i >= 0 and a.digits[i] == b.digits[i]:
             i -= 1
         if i < 0:
-            return W_LongObject(a.space, [r_uint(0)], 0)
-        if a._getshort(i) < b._getshort(i):
+            return W_LongObject(a.space, [Digit(0)], 0)
+        if a.digits[i] < b.digits[i]:
             sign = -1
             a, b = b, a
         size_a = size_b = i+1
-    digitpairs = (size_a + 1) // 2
-    z = W_LongObject(a.space, [r_uint(0)] * digitpairs, 1)
+    z = W_LongObject(a.space, [Digit(0)] * size_a, 1)
     i = 0
     while i < size_b:
         # The following assumes unsigned arithmetic
         # works modulo 2**N for some N>SHIFT.
-        borrow = a._getshort(i) - b._getshort(i) - borrow
-        z._setshort(i, borrow & MASK)
+        borrow = a.digits[i] - b.digits[i] - borrow
+        z.digits[i] = borrow & MASK
         borrow >>= SHIFT
         borrow &= 1 # Keep only one sign bit
         i += 1
     while i < size_a:
-        borrow = a._getshort(i) - borrow
-        z._setshort(i, borrow & MASK)
+        borrow = a.digits[i] - borrow
+        z.digits[i] = borrow & MASK
         borrow >>= SHIFT
         borrow &= 1 # Keep only one sign bit
         i += 1
@@ -599,24 +605,24 @@
 
 #Multiply the absolute values of two longs
 def _x_mul(a, b):
-    size_a = len(a.digits) * 2
-    size_b = len(b.digits) * 2
-    z = W_LongObject(a.space, [r_uint(0)] * ((size_a + size_b) // 2), 1)
+    size_a = len(a.digits)
+    size_b = len(b.digits)
+    z = W_LongObject(a.space, [Digit(0)] * (size_a + size_b), 1)
     i = 0
     while i < size_a:
-        carry = r_uint(0)
-        f = a._getshort(i)
+        carry = Carrymul(0)
+        f = Twodigits(a.digits[i])
         j = 0
         while j < size_b:
-            carry += z._getshort(i + j) + b._getshort(j) * f
-            z._setshort(i + j, carry & MASK)
+            carry += z.digits[i + j] + b.digits[j] * f
+            z.digits[i + j] = carry & MASK
             carry = carry >> SHIFT
             j += 1
         while carry != 0:
             assert i + j < size_a + size_b
-            carry += z._getshort(i + j)
-            z._setshort(i + j, carry & MASK)
-            carry = carry >> SHIFT
+            carry += z.digits[i + j]
+            z.digits[i + j] = carry & MASK
+            carry >>= SHIFT
             j += 1
         i += 1
     z._normalize()
@@ -627,15 +633,15 @@
     Divide long pin by non-zero digit n, storing quotient
     in pout, and returning the remainder. It's OK for pin == pout on entry.
     """
-    rem = r_uint(0)
+    rem = Twodigits(0)
     assert n > 0 and n <= MASK
     if not size:
-        size = len(pin.digits) * 2
+        size = len(pin.digits)
     size -= 1
     while size >= 0:
-        rem = (rem << SHIFT) + pin._getshort(size)
+        rem = (rem << SHIFT) + pin.digits[size]
         hi = rem // n
-        pout._setshort(size, hi)
+        pout.digits[size] = hi
         rem -= hi * n
         size -= 1
     return rem
@@ -648,7 +654,7 @@
     """
     assert n > 0 and n <= MASK
     size = len(a.digits)
-    z = W_LongObject(a.space, [r_uint(0)] * size, 1)
+    z = W_LongObject(a.space, [Digit(0)] * size, 1)
     rem = _inplace_divrem1(z, a, n)
     z._normalize()
     return z, rem
@@ -656,19 +662,16 @@
 def _muladd1(a, n, extra):
     """Multiply by a single digit and add a single digit, ignoring the sign.
     """
-    digitpairs = len(a.digits)
-    size_a = digitpairs * 2
-    if a._getshort(size_a-1) == 0:
-        size_a -= 1
-    z = W_LongObject(a.space, [r_uint(0)] * (digitpairs+1), 1)
-    carry = extra
+    size_a = len(a.digits)
+    z = W_LongObject(a.space, [Digit(0)] * (size_a+1), 1)
+    carry = Carrymul(extra)
     i = 0
     while i < size_a:
-        carry += a._getshort(i) * n
-        z._setshort(i, carry & MASK)
+        carry += Twodigits(a.digits[i]) * n
+        z.digits[i] = carry & MASK
         carry >>= SHIFT
         i += 1
-    z._setshort(i, carry)
+    z.digits[i] = carry
     z._normalize()
     return z
 
@@ -681,14 +684,17 @@
 # be used recursively to implement longs of any size.
 
 class r_suint(object):
-    # we do not inherit from r_uint, because we only
+    # we do not inherit from Digit, because we only
     # support a few operations for our purpose
+    BITS = Twodigits.BITS
+    MASK = Twodigits.MASK
+
     def __init__(self, value=0):
         if isinstance(value, r_suint):
             self.value = value.value
             self.sign = value.sign
         else:
-            self.value = r_uint(value)
+            self.value = Twodigits(value)
             self.sign = -(value < 0)
 
     def longval(self):
@@ -728,7 +734,7 @@
     def __irshift__(self, n):
         self.value >>= n
         if self.sign:
-            self.value += r_uint(LONG_MASK) << (LONG_BIT - n)
+            self.value += self.MASK << (self.BITS - n)
         return self
 
     def __rshift__(self, n):
@@ -750,85 +756,89 @@
         return self.value & mask
 
     def __eq__(self, other):
-        if not isinstance(other,r_suint):
+        if not isinstance(other, r_suint):
             other = r_suint(other)
         return self.sign == other.sign and self.value == other.value
 
+    def __ne__(self, other):
+        return not self == other
+
 def _x_divrem(v1, w1):
-    size_w = len(w1.digits) * 2
-    # hack for the moment:
-    # find where w1 is really nonzero
-    if w1._getshort(size_w-1) == 0:
-        size_w -= 1
-    d = (MASK+1) // (w1._getshort(size_w-1) + 1)
-    v = _muladd1(v1, d, r_uint(0))
-    w = _muladd1(w1, d, r_uint(0))
-    size_v = len(v.digits) * 2
-    if v._getshort(size_v-1) == 0:
-        size_v -= 1
-    size_w = len(w.digits) * 2
-    if w._getshort(size_w-1) == 0:
-        size_w -= 1
+    size_w = len(w1.digits)
+    d = (MASK+1) // (w1.digits[size_w-1] + 1)
+    v = _muladd1(v1, d, Digit(0))
+    w = _muladd1(w1, d, Digit(0))
+    size_v = len(v.digits)
+    size_w = len(w.digits)
     assert size_v >= size_w and size_w > 1 # Assert checks by div()
 
     size_a = size_v - size_w + 1
-    digitpairs = (size_a + 1) // 2
-    a = W_LongObject(v.space, [r_uint(0)] * digitpairs, 1)
+    a = W_LongObject(v.space, [Digit(0)] * size_a, 1)
 
     j = size_v
     k = size_a - 1
     while k >= 0:
         if j >= size_v:
-            vj = r_uint(0)
+            vj = Digit(0)
         else:
-            vj = v._getshort(j)
+            vj = v.digits[j]
         carry = r_suint(0) # note: this must hold two digits and a sign!
 
-        if vj == w._getshort(size_w-1):
-            q = r_uint(MASK)
+        if vj == w.digits[size_w-1]:
+            q = Twodigits(MASK)
         else:
-            q = ((vj << SHIFT) + v._getshort(j-1)) // w._getshort(size_w-1)
+            q = ((Twodigits(vj) << SHIFT) + v.digits[j-1]) // w.digits[size_w-1]
 
         # notabene!
         # this check needs a signed two digits result
         # or we get an overflow.
-        while (w._getshort(size_w-2) * q >
+        while (w.digits[size_w-2] * q >
                 ((
                     r_suint(vj << SHIFT) # this one dominates
-                    + v._getshort(j-1)
-                    - long(q) * long(w._getshort(size_w-1))
+                    + v.digits[j-1]
+                    - long(q) * long(w.digits[size_w-1])
                                 ) << SHIFT)
-                + v._getshort(j-2)):
+                + v.digits[j-2]):
             q -= 1
         i = 0
         while i < size_w and i+k < size_v:
-            z = w._getshort(i) * q
+            z = w.digits[i] * q
             zz = z >> SHIFT
-            carry += v._getshort(i+k) + (zz << SHIFT)
+            carry += v.digits[i+k] + (zz << SHIFT)
             carry -= z
             if hasattr(carry, 'value'):
-                v._setshort(i+k, r_uint(carry.value & MASK))
+                v.digits[i+k] = Digit(carry.value & MASK)
             else:
-                v._setshort(i+k, r_uint(carry & MASK))
+                v.digits[i+k] = Digit(carry & MASK)
             carry >>= SHIFT
             carry -= zz
             i += 1
 
         if i+k < size_v:
-            carry += v._getshort(i+k)
-            v._setshort(i+k, r_uint(0))
+            carry += v.digits[i+k]
+            v.digits[i+k] = Digit(0)
 
         if carry == 0:
-            a._setshort(k, q & MASK)
+            a.digits[k] = q & MASK
+            assert not q >> SHIFT
         else:
-            ##!!assert carry == -1
-            a._setshort(k, (q-1) & MASK)
+            #assert carry == -1
+            if carry != -1:
+                print 70*"*"
+                print "CARRY", carry
+                print "comparison:", carry == -1
+                print hex(v1.longval())
+                print hex(w1.longval())
+                print 70*"*"
+            q -= 1
+            a.digits[k] = q-1 & MASK
+            assert not q >> SHIFT
 
             carry = r_suint(0)
             i = 0
             while i < size_w and i+k < size_v:
-                carry += v._getshort(i+k) + w._getshort(i)
-                v._setshort(i+k, r_uint(carry.value) & MASK)
+                carry += v.digits[i+k] + w.digits[i]
+                v.digits[i+k] = Digit(carry.value) & MASK
                 carry >>= SHIFT
                 i += 1
         j -= 1
@@ -841,12 +851,8 @@
 
 def _divrem(a, b):
     """ Long division with remainder, top-level routine """
-    size_a = len(a.digits) * 2
-    size_b = len(b.digits) * 2
-    if a._getshort(size_a-1) == 0:
-        size_a -= 1
-    if b._getshort(size_b-1) == 0:
-        size_b -= 1
+    size_a = len(a.digits)
+    size_b = len(b.digits)
 
     if b.sign == 0:
         raise OperationError(a.space.w_ZeroDivisionError,
@@ -854,13 +860,13 @@
 
     if (size_a < size_b or
         (size_a == size_b and
-         a._getshort(size_a-1) < b._getshort(size_b-1))):
+         a.digits[size_a-1] < b.digits[size_b-1])):
         # |a| < |b|
-        z = W_LongObject(a.space, [r_uint(0)], 0)
+        z = W_LongObject(a.space, [Digit(0)], 0)
         rem = a
         return z, rem
     if size_b == 1:
-        z, urem = _divrem1(a, b._getshort(0))
+        z, urem = _divrem1(a, b.digits[0])
         rem = W_LongObject(a.space, [urem], int(urem != 0))
     else:
         z, rem = _x_divrem(a, b)
@@ -892,16 +898,14 @@
     multiplier = float(1 << SHIFT)
     if v.sign == 0:
         return 0.0, 0
-    i = len(v.digits) * 2 - 1
-    if v._getshort(i) == 0:
-        i -= 1
+    i = len(v.digits) - 1
     sign = v.sign
-    x = float(v._getshort(i))
+    x = float(v.digits[i])
     nbitsneeded = NBITS_WANTED - 1
     # Invariant:  i Python digits remain unaccounted for.
     while i > 0 and nbitsneeded > 0:
         i -= 1
-        x = x * multiplier + float(v._getshort(i))
+        x = x * multiplier + float(v.digits[i])
         nbitsneeded -= SHIFT
     # There are i digits we didn't shift in.  Pretending they're all
     # zeroes, the true value is x * 2**(i*SHIFT).
@@ -915,12 +919,12 @@
 ##def ldexp(x, exp):
 ##    assert type(x) is float
 ##    lb1 = LONG_BIT - 1
-##    multiplier = float(r_uint(1) << lb1)
+##    multiplier = float(Digit(1) << lb1)
 ##    while exp >= lb1:
 ##        x *= multiplier
 ##        exp -= lb1
 ##    if exp:
-##        x *= float(r_uint(1) << exp)
+##        x *= float(Digit(1) << exp)
 ##    return x
 
 # note that math.ldexp checks for overflows,
@@ -973,14 +977,13 @@
         dval = -dval
     frac, expo = math.frexp(dval) # dval = frac*2**expo; 0.0 <= frac < 1.0
     if expo <= 0:
-        return W_LongObject(space, [r_uint(0)], 0)
+        return W_LongObject(space, [Digit(0)], 0)
     ndig = (expo-1) // SHIFT + 1 # Number of 'digits' in result
-    digitpairs = (ndig + 1) // 2
-    v = W_LongObject(space, [r_uint(0)] * digitpairs, 1)
+    v = W_LongObject(space, [Digit(0)] * ndig, 1)
     frac = math.ldexp(frac, (expo-1) % SHIFT + 1)
     for i in range(ndig-1, -1, -1):
         bits = int(frac)
-        v._setshort(i, r_uint(bits))
+        v.digits[i] = Digit(bits)
         frac -= float(bits)
         frac = math.ldexp(frac, SHIFT)
     if neg:
@@ -1007,7 +1010,7 @@
     div, mod = _divrem(v, w)
     if mod.sign * w.sign == -1:
         mod = add__Long_Long(v.space, mod, w)
-        one = W_LongObject(v.space, [r_uint(1)], 1)
+        one = W_LongObject(v.space, [Digit(1)], 1)
         div = sub__Long_Long(v.space, div, one)
     return div, mod
 
@@ -1018,9 +1021,7 @@
     Return a string object.
     If base is 8 or 16, add the proper prefix '0' or '0x'.
     """
-    size_a = len(a.digits) * 2
-    if a._getshort(size_a-1) == 0:
-        size_a -= 1
+    size_a = len(a.digits)
 
     assert base >= 2 and base <= 36
 
@@ -1046,7 +1047,7 @@
         s[p] = '0'
     elif (base & (base - 1)) == 0:
         # JRH: special case for power-of-2 bases
-        accum = r_uint(0)
+        accum = Twodigits(0)
         accumbits = 0  # # of bits in accum 
         basebits = 1   # # of bits in base-1
         i = base
@@ -1057,7 +1058,7 @@
             basebits += 1
 
         for i in range(size_a):
-            accum |= a._getshort(i) << accumbits
+            accum |= Twodigits(a.digits[i]) << accumbits
             accumbits += SHIFT
             assert accumbits >= basebits
             while 1:
@@ -1084,25 +1085,24 @@
         size = size_a
         pin = a # just for similarity to C source which uses the array
         # powbase <- largest power of base that fits in a digit.
-        powbase = base  # powbase == base ** power
+        powbase = Digit(base)  # powbase == base ** power
         power = 1
         while 1:
-            newpow = powbase * r_uint(base)
+            newpow = powbase * Digit(base)
             if newpow >> SHIFT:  # doesn't fit in a digit
                 break
             powbase = newpow
             power += 1
 
         # Get a scratch area for repeated division.
-        digitpairs = (size + 1) // 2
-        scratch = W_LongObject(a.space, [r_uint(0)] * digitpairs, 1)
+        scratch = W_LongObject(a.space, [Digit(0)] * size, 1)
 
         # Repeatedly divide by powbase.
         while 1:
             ntostore = power
             rem = _inplace_divrem1(scratch, pin, powbase, size)
             pin = scratch  # no need to use a again
-            if pin._getshort(size - 1) == 0:
+            if pin.digits[size - 1] == 0:
                 size -= 1
 
             # Break rem into digits.
@@ -1159,14 +1159,14 @@
 
     if a.sign < 0:
         a = invert__Long(a.space, a)
-        maska = r_uint(MASK)
+        maska = Digit(MASK)
     else:
-        maska = r_uint(0)
+        maska = Digit(0)
     if b.sign < 0:
         b = invert__Long(b.space, b)
-        maskb = r_uint(MASK)
+        maskb = Digit(MASK)
     else:
-        maskb = r_uint(0)
+        maskb = Digit(0)
 
     negz = 0
     if op == '^':
@@ -1195,12 +1195,8 @@
     # iff one of these cases applies, and mask will be non-0 for operands
     # whose length should be ignored.
 
-    size_a = len(a.digits) * 2
-    if a._getshort(size_a - 1) == 0:
-        size_a -= 1
-    size_b = len(b.digits) * 2
-    if b._getshort(size_b - 1) == 0:
-        size_b -= 1
+    size_a = len(a.digits)
+    size_b = len(b.digits)
     if op == '&':
         if maska:
             size_z = size_b
@@ -1212,26 +1208,51 @@
     else:
         size_z = max(size_a, size_b)
 
-    digitpairs = (size_z + 1) // 2
-    z = W_LongObject(a.space, [r_uint(0)] * digitpairs, 1)
+    z = W_LongObject(a.space, [Digit(0)] * size_z, 1)
 
     for i in range(size_z):
         if i < size_a:
-            diga = a._getshort(i) ^ maska
+            diga = a.digits[i] ^ maska
         else:
             diga = maska
         if i < size_b:
-            digb = b._getshort(i) ^ maskb
+            digb = b.digits[i] ^ maskb
         else:
             digb = maskb
         if op == '&':
-            z._setshort(i, diga & digb)
+            z.digits[i] = diga & digb
         elif op == '|':
-            z._setshort(i, diga | digb)
+            z.digits[i] = diga | digb
         elif op == '^':
-            z._setshort(i, diga ^ digb)
+            z.digits[i] = diga ^ digb
 
     z._normalize()
     if negz == 0:
         return z
     return invert__Long(z.space, z)
+
+def _AsLong(v):
+    """
+    Get an integer from a long int object.
+    Returns -1 and sets an error condition if overflow occurs.
+    """
+    # This version by Tim Peters
+    i = len(v.digits) - 1
+    sign = v.sign
+    if not sign:
+        return 0
+    x = r_uint(0)
+    while i >= 0:
+        prev = x
+        x = (x << SHIFT) + v.digits[i]
+        if (x >> SHIFT) != prev:
+            raise OverflowError
+        i -= 1
+
+    # Haven't lost any bits, but if the sign bit is set we're in
+    # trouble *unless* this is the min negative number.  So,
+    # trouble iff sign bit set && (positive || some bit set other
+    # than the sign bit).
+    if int(x) < 0 and (sign > 0 or (x << 1) != 0):
+            raise OverflowError
+    return intmask(int(x) * sign)



More information about the Pypy-commit mailing list