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

tismer at codespeak.net tismer at codespeak.net
Tue Jul 5 19:30:56 CEST 2005


Author: tismer
Date: Tue Jul  5 19:30:56 2005
New Revision: 14304

Modified:
   pypy/dist/pypy/objspace/std/longobject.py
Log:
waaaah!
fixed a very hard to detect bug, which occours when
we are using all bits of a two digits word.
The C source does not say this explicitly, but uses
a weird expression that only works if a basic type
can hold a sign plus two digits.
Implemented this with r_suint.

too bad, this took many hours to deduce.

Modified: pypy/dist/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longobject.py	(original)
+++ pypy/dist/pypy/objspace/std/longobject.py	Tue Jul  5 19:30:56 2005
@@ -9,7 +9,7 @@
 import math
 
 SHORT_BIT = int(LONG_BIT // 2)
-SHORT_MASK = int(LONG_MASK >> SHORT_BIT)
+SHORT_MASK = int((1 << SHORT_BIT) - 1)
 
 SIGN_BIT = LONG_BIT-1
 SIGN_MASK = r_uint(1) << SIGN_BIT
@@ -63,7 +63,8 @@
 
     def _setshort(self, index, short):
         a = self.digits[index // 2]
-        assert isinstance(short, r_uint)
+        ##!!assert isinstance(short, r_uint)
+        assert short & SHORT_MASK == short
         if index % 2 == 0:
             self.digits[index // 2] = ((a >> SHORT_BIT) << SHORT_BIT) + short
         else:
@@ -727,6 +728,15 @@
         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
@@ -736,7 +746,7 @@
             other = r_suint(other)
         return self.sign == other.sign and self.value == other.value
 
-def _x_divrem(space, v1, w1): # return as tuple, PyLongObject **prem)
+def _x_divrem(space, v1, w1):
     size_w = len(w1.digits) * 2
     # hack for the moment:
     # find where w1 is really nonzero
@@ -756,8 +766,10 @@
     size_a = size_v - size_w + 1
     digitpairs = (size_a + 1) // 2
     a = W_LongObject(space, [r_uint(0)] * digitpairs, 1)
+
     j = size_v
-    for k in range(size_a-1, -1, -1):
+    k = size_a - 1
+    while k >= 0:
         if j >= size_v:
             vj = r_uint(0)
         else:
@@ -769,18 +781,20 @@
         else:
             q = ((vj << SHORT_BIT) + v._getshort(j-1)) // w._getshort(size_w-1)
 
+        # notabene!
+        # this check needs a signed two digits result
+        # or we get an overflow.
         while (w._getshort(size_w-2) * q >
                 ((
-                    (vj << SHORT_BIT)
+                    r_suint(vj << SHORT_BIT) # this one dominates
                     + v._getshort(j-1)
                     - q * w._getshort(size_w-1)
                                 ) << SHORT_BIT)
                 + v._getshort(j-2)):
             q -= 1
 
-        for i in range(size_w):
-            if i+k >= size_v:
-                break
+        i = 0
+        while i < size_w and i+k < size_v:
             z = w._getshort(i) * q
             zz = z >> SHORT_BIT
             carry += v._getshort(i+k) + (zz << SHORT_BIT)
@@ -788,8 +802,8 @@
             v._setshort(i+k, r_uint(carry.value & SHORT_MASK))
             carry >>= SHORT_BIT
             carry -= zz
+            i += 1
 
-        i += 1 # compare C code which re-uses i of loop
         if i+k < size_v:
             carry += v._getshort(i+k)
             v._setshort(i+k, r_uint(0))
@@ -797,18 +811,18 @@
         if carry == 0:
             a._setshort(k, q)
         else:
-            #assert carry == -1
-            # the above would hold if we didn't minimize size_w
+            assert carry == -1
             a._setshort(k, q-1)
-            carry = r_suint(0)
 
-            for i in range(size_w):
-                if i+k >= size_v:
-                    break
+            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) & SHORT_MASK)
+                v._setshort(i+k, r_uint(carry.value) & SHORT_MASK)
                 carry >>= SHORT_BIT
+                i += 1
         j -= 1
+        k -= 1
 
     a._normalize()
     rem, _ = _divrem1(space, v, d)



More information about the Pypy-commit mailing list