[pypy-svn] r14412 - in pypy/dist/pypy: objspace/std objspace/std/test rpython

tismer at codespeak.net tismer at codespeak.net
Thu Jul 7 21:48:16 CEST 2005


Author: tismer
Date: Thu Jul  7 21:48:14 2005
New Revision: 14412

Modified:
   pypy/dist/pypy/objspace/std/longobject.py
   pypy/dist/pypy/objspace/std/test/test_longobject.py
   pypy/dist/pypy/rpython/rarithmetic.py
Log:
long objects are complete and pass all tests.

Karatsuba isn't done, yet.
Also we are currently stuck with 15 bits, because
long division needs a signed type that can hold two digits *and* a sign.

Temporarily, I had an extra class to emulate this, and all algorithms
are tested to work at full bit size. I removed the class because
I was not pleased with the overhead.


Modified: pypy/dist/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longobject.py	(original)
+++ pypy/dist/pypy/objspace/std/longobject.py	Thu Jul  7 21:48:14 2005
@@ -13,17 +13,23 @@
 
 Digit = r_uint # already works: r_ushort
 Twodigits = r_uint
-Stwodigits = int
 
 # the following describe a plain digit
+# XXX at the moment we can't save this bit,
+# or we would need a large enough type to hold
+# the carry bits in _x_divrem
 SHIFT = (Twodigits.BITS // 2) - 1
 MASK = int((1 << SHIFT) - 1)
 
 # find the correct type for carry/borrow
-if Digit.BITS - SHIFT > 0:
+if Digit.BITS - SHIFT >= 1:
+    # we have one more bit in Digit
     Carryadd = Digit
+    Stwodigits = int
 else:
+    # we need another Digit
     Carryadd = Twodigits
+    raise ValueError, "need a large enough type for Stwodigits"
 Carrymul = Twodigits
 
 # Debugging digit array access.
@@ -31,7 +37,7 @@
 # 0 == no check at all
 # 1 == check correct type
 # 2 == check for extra (ab)used bits
-CHECK_DIGITS = 1
+CHECK_DIGITS = 2
 
 if CHECK_DIGITS:
     class DigitArray(list):
@@ -560,16 +566,16 @@
     i = 0
     carry = Carryadd(0)
     while i < size_b:
-        carry += a.digits[i] + b.digits[i]
-        z.digits[i] = carry & MASK
+        carry += Carryadd(a.digits[i]) + b.digits[i]
+        z.digits[i] = Digit(carry & MASK)
         carry >>= SHIFT
         i += 1
     while i < size_a:
         carry += a.digits[i]
-        z.digits[i] = carry & MASK
+        z.digits[i] = Digit(carry & MASK)
         carry >>= SHIFT
         i += 1
-    z.digits[i] = carry
+    z.digits[i] = Digit(carry)
     z._normalize()
     return z
 
@@ -578,12 +584,12 @@
     size_a = len(a.digits)
     size_b = len(b.digits)
     sign = 1
-    borrow = Digit(0)
+    borrow = Carryadd(0)
 
     # Ensure a is the larger of the two:
     if size_a < size_b:
         sign = -1
-        a,b=b, a
+        a, b = b, a
         size_a, size_b = size_b, size_a
     elif size_a == size_b:
         # Find highest digit where a and b differ:
@@ -601,14 +607,14 @@
     while i < size_b:
         # The following assumes unsigned arithmetic
         # works modulo 2**N for some N>SHIFT.
-        borrow = a.digits[i] - b.digits[i] - borrow
-        z.digits[i] = borrow & MASK
+        borrow = Carryadd(a.digits[i]) - b.digits[i] - borrow
+        z.digits[i] = Digit(borrow & MASK)
         borrow >>= SHIFT
         borrow &= 1 # Keep only one sign bit
         i += 1
     while i < size_a:
         borrow = a.digits[i] - borrow
-        z.digits[i] = borrow & MASK
+        z.digits[i] = Digit(borrow & MASK)
         borrow >>= SHIFT
         borrow &= 1 # Keep only one sign bit
         i += 1
@@ -631,13 +637,13 @@
         j = 0
         while j < size_b:
             carry += z.digits[i + j] + b.digits[j] * f
-            z.digits[i + j] = carry & MASK
-            carry = carry >> SHIFT
+            z.digits[i + j] = Digit(carry & MASK)
+            carry >>= SHIFT
             j += 1
         while carry != 0:
             assert i + j < size_a + size_b
             carry += z.digits[i + j]
-            z.digits[i + j] = carry & MASK
+            z.digits[i + j] = Digit(carry & MASK)
             carry >>= SHIFT
             j += 1
         i += 1
@@ -657,7 +663,7 @@
     while size >= 0:
         rem = (rem << SHIFT) + pin.digits[size]
         hi = rem // n
-        pout.digits[size] = hi
+        pout.digits[size] = Digit(hi)
         rem -= hi * n
         size -= 1
     return rem
@@ -684,102 +690,16 @@
     i = 0
     while i < size_a:
         carry += Twodigits(a.digits[i]) * n
-        z.digits[i] = carry & MASK
+        z.digits[i] = Digit(carry & MASK)
         carry >>= SHIFT
         i += 1
-    z.digits[i] = carry
+    z.digits[i] = Digit(carry)
     z._normalize()
     return z
 
-# for the carry in _x_divrem, we need something that can hold
-# two digits plus a sign.
-# for the time being, we here implement such a 33 bit number just
-# for the purpose of the division.
-# In the long term, it might be considered to implement the
-# notation of a "double anything" unsigned type, which could
-# be used recursively to implement longs of any size.
-
-class r_suint(object):
-    # 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 = Twodigits(value)
-            self.sign = -(value < 0)
-
-    def longval(self):
-        if self.sign:
-            return -long(-self.value)
-        else:
-            return long(self.value)
-        
-    def __repr__(self):
-        return repr(self.longval())
-
-    def __str__(self):
-        return str(self.longval())
-
-    def __iadd__(self, other):
-        hold = self.value
-        self.value += other
-        self.sign ^= - ( (other < 0) != (self.value < hold) )
-        return self
-
-    def __add__(self, other):
-        res = r_suint(self)
-        res += other
-        return res
-
-    def __isub__(self, other):
-        hold = self.value
-        self.value -= other
-        self.sign ^= - ( (other < 0) != (self.value > hold) )
-        return self
-
-    def __sub__(self, other):
-        res = r_suint(self)
-        res -= other
-        return res
-
-    def __irshift__(self, n):
-        self.value >>= n
-        if self.sign:
-            self.value += self.MASK << (self.BITS - n)
-        return self
-
-    def __rshift__(self, n):
-        res = r_suint(self)
-        res >>= n
-        return res
-
-    def __ilshift__(self, n):
-        self.value <<= n
-        return self
-
-    def __lshift__(self, n):
-        res = r_suint(self)
-        res <<= n
-        return res
-
-    def __and__(self, mask):
-        # only used to get bits from the value
-        return self.value & mask
-
-    def __eq__(self, other):
-        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):
+    """ Unsigned long division with remainder -- the algorithm """
     size_w = len(w1.digits)
     d = Digit(Twodigits(MASK+1) // (w1.digits[size_w-1] + 1))
     v = _muladd1(v1, d, Digit(0))
@@ -798,7 +718,7 @@
             vj = Digit(0)
         else:
             vj = v.digits[j]
-        carry = r_suint(0) # note: this must hold two digits and a sign!
+        carry = Stwodigits(0) # note: this must hold two digits and a sign!
 
         if vj == w.digits[size_w-1]:
             q = Twodigits(MASK)
@@ -810,51 +730,40 @@
         # or we get an overflow.
         while (w.digits[size_w-2] * q >
                 ((
-                    r_suint(vj << SHIFT) # this one dominates
-                    + v.digits[j-1]
-                    - long(q) * long(w.digits[size_w-1])
+                    (Stwodigits(vj) << SHIFT) # this one dominates
+                    + Stwodigits(v.digits[j-1])
+                    - Stwodigits(q) * Stwodigits(w.digits[size_w-1])
                                 ) << SHIFT)
-                + v.digits[j-2]):
+                + Stwodigits(v.digits[j-2])):
             q -= 1
         i = 0
         while i < size_w and i+k < size_v:
-            z = w.digits[i] * q
+            z = Stwodigits(w.digits[i] * q)
             zz = z >> SHIFT
-            carry += v.digits[i+k] + (zz << SHIFT)
-            carry -= z
-            if hasattr(carry, 'value'):
-                v.digits[i+k] = Digit(carry.value & MASK)
-            else:
-                v.digits[i+k] = Digit(carry & MASK)
+            carry += Stwodigits(v.digits[i+k]) - z + (zz << SHIFT)
+            v.digits[i+k] = Digit(carry & MASK)
             carry >>= SHIFT
             carry -= zz
             i += 1
 
         if i+k < size_v:
-            carry += v.digits[i+k]
+            carry += Stwodigits(v.digits[i+k])
             v.digits[i+k] = Digit(0)
 
         if carry == 0:
-            a.digits[k] = q & MASK
+            a.digits[k] = Digit(q & MASK)
             assert not q >> SHIFT
         else:
-            #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*"*"
+            assert carry == -1
             q -= 1
-            a.digits[k] = q-1 & MASK
+            a.digits[k] = Digit(q & MASK)
             assert not q >> SHIFT
 
-            carry = r_suint(0)
+            carry = Stwodigits(0)
             i = 0
             while i < size_w and i+k < size_v:
-                carry += v.digits[i+k] + w.digits[i]
-                v.digits[i+k] = Digit(carry.value) & MASK
+                carry += Stwodigits(v.digits[i+k]) + Stwodigits(w.digits[i])
+                v.digits[i+k] = Digit(carry & MASK)
                 carry >>= SHIFT
                 i += 1
         j -= 1
@@ -1049,7 +958,7 @@
     while i > 1:
         bits += 1
         i >>= 1
-    i = 5 + int(bool(addL)) + (size_a*LONG_BIT + bits-1) // bits
+    i = 5 + int(bool(addL)) + (size_a*SHIFT + bits-1) // bits
     s = [chr(0)] * i
     p = i
     if addL:
@@ -1104,10 +1013,10 @@
         powbase = Digit(base)  # powbase == base ** power
         power = 1
         while 1:
-            newpow = powbase * Digit(base)
+            newpow = Twodigits(powbase) * Digit(base)
             if newpow >> SHIFT:  # doesn't fit in a digit
                 break
-            powbase = newpow
+            powbase = Digit(newpow)
             power += 1
 
         # Get a scratch area for repeated division.
@@ -1144,7 +1053,7 @@
                 break
 
     if base == 8:
-        if size_a != 0:
+        if a.sign != 0:
             p -= 1
             s[p] = '0'
     elif base == 16:

Modified: pypy/dist/pypy/objspace/std/test/test_longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_longobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_longobject.py	Thu Jul  7 21:48:14 2005
@@ -329,7 +329,6 @@
         y >>= s2*16
         x = 0x3FE0003FFFFC0001FFFL
         y = 0x9800FFC1L
-        print "special case"
         check_division(x, y)
         raises(ZeroDivisionError, "x // 0L")
 

Modified: pypy/dist/pypy/rpython/rarithmetic.py
==============================================================================
--- pypy/dist/pypy/rpython/rarithmetic.py	(original)
+++ pypy/dist/pypy/rpython/rarithmetic.py	Thu Jul  7 21:48:14 2005
@@ -328,10 +328,12 @@
         return _widen(self, other, res)
 
 class r_ushort(r_uint):
+    """ fake unsigned short integer implementation """
     BITS = r_uint.BITS // 2
     MASK = (1L << BITS) - 1
 
 class r_ulong(r_uint):
+    """ fake unsigned long integer implementation """
     BITS = r_uint.BITS * 2
     MASK = (1L << BITS) - 1
 



More information about the Pypy-commit mailing list