Example #1
0
def _PyLong_FromByteArray(space, bytes, n, little_endian, signed):
    little_endian = rffi.cast(lltype.Signed, little_endian)
    signed = rffi.cast(lltype.Signed, signed)

    result = rbigint()
    negative = False

    for i in range(0, n):
        if little_endian:
            c = intmask(bytes[i])
        else:
            c = intmask(bytes[n - i - 1])
        if i == 0 and signed and c & 0x80:
            negative = True
        if negative:
            c = c ^ 0xFF
        digit = rbigint.fromint(c)

        result = result.lshift(8)
        result = result.add(digit)

    if negative:
        result = result.neg()

    return space.newlong_from_rbigint(result)
Example #2
0
def _rbigint_rshift(value, shamt):
    if not value.sign or not shamt.sign: return value
    if shamt.numdigits() > 1: return NULLRBIGINT
    shamt = shamt.digit(0)

    wordshift = shamt / SHIFT
    newsize = value.numdigits() - wordshift
    if newsize <= 0: return NULLRBIGINT

    loshift = shamt - wordshift * SHIFT
    hishift = SHIFT - loshift
    ret = rbigint([NULLDIGIT] * newsize, 1, newsize)

    i = 0
    lastidx = newsize - 1
    curword = value.digit(wordshift)
    while i < lastidx:
        newdigit = curword >> loshift
        wordshift = wordshift + 1
        curword = value.digit(wordshift)
        ret.setdigit(i, newdigit | (curword << hishift))
        i += 1
    # last digit
    ret.setdigit(i, curword >> loshift)

    ret._normalize()
    return ret
Example #3
0
    def descr_int(self, space):  # TODO
        index = self.nbits - 1
        bigval = self.bigval
        wordpos = index / SHIFT
        if wordpos > bigval.numdigits(
        ):  # msb must be zero, number is positive
            return self.descr_uint(space)

        bitpos = index - wordpos * SHIFT
        word = bigval.digit(wordpos)
        msb = (word >> bitpos) & 1
        if not msb:
            return newlong(space, bigval)

        # calculate self.nbits's index
        bitpos += 1
        if bitpos == SHIFT:
            wordpos += 1
            bitpos = 0

        # manually assemble (1 << (index+1))
        shift = rbigint([NULLDIGIT] * wordpos + [_store_digit(1 << bitpos)], 1,
                        wordpos + 1)

        res = bigval.sub(shift)
        return newlong(space, res)
Example #4
0
 def __init__(self, itemlist):
     self.value = {}
     self.keys = []
     i = 0
     while i < len(itemlist):
         self.value[itemlist[i].str()] = itemlist[i + 1]
         self.keys.append(itemlist[i])
         i += 2
     a = rbigint()
     self.length = SodaInt(a.fromint(len(self.value)))
Example #5
0
def _rbigint_setidx(value, index, other):
    size = value.numdigits()
    wordpos = index / SHIFT

    if wordpos >= size:
        if not other:
            return value

        bitpos = index - wordpos * SHIFT
        shift = 1 << bitpos
        return rbigint( value._digits[:size] + \
                        [NULLDIGIT]*(wordpos-size) + \
                        [_store_digit(shift)], 1, wordpos + 1 )

    # wordpos < size
    digit = value.digit(wordpos)
    bitpos = index - wordpos * SHIFT
    shift = 1 << bitpos

    if other == 1:
        if digit & shift:  # already 1
            return value
        # the value is changed
        ret = rbigint(value._digits[:size], 1, size)
        ret.setdigit(wordpos, digit | shift)
        return ret
    # other == 0

    if not (digit & shift):  # already 0
        return value
    # the value is changed
    digit ^= shift
    if digit == 0 and wordpos == size - 1:
        assert wordpos >= 0
        return rbigint(value._digits[:wordpos] + [NULLDIGIT], 1, wordpos)

    ret = rbigint(value._digits[:size], 1, size)
    ret.setdigit(wordpos, digit)
    return ret
Example #6
0
def expression_normalizedarray(s):
    sourcepos = s[0].getsourcepos()
    package = fetcher.packages[sourcepos.idx]
    line = str(sourcepos.lineno)
    col = str(sourcepos.colno)
    lst = s[1].get()
    enumlist = []
    a = rbigint()
    for i in range(0, len(lst)):
        enumlist.append(ast.Integer(a.fromint(i), package, line, col))
        enumlist.append(lst[i])
    enumlist.reverse()
    return ast.Array(enumlist, package, line, col)
Example #7
0
 def create_arrays(self, text):
     self.textarrays = []
     chars, words, lines = [], [], []
     wordbuffer, linebuffer = [], []
     i, j, k = 0, 0, 0
     a = rbigint()
     text, trash = str_decode_utf_8(text, len(text), "strict", True)
     for char in text:
         if char == " " and wordbuffer != []:
             word = u"".join(wordbuffer)
             words.append(SodaInt(a.fromint(j)))
             words.append(SodaString(word))
             wordbuffer = []
             j += 1
             chars.append(SodaInt(a.fromint(i)))
             chars.append(SodaString(char))
             linebuffer.append(char)
             i += 1
         elif char == "\n" and linebuffer != []:
             line = u"".join(linebuffer)
             lines.append(SodaInt(a.fromint(k)))
             lines.append(SodaString(line))
             linebuffer = []
             k += 1
             if not wordbuffer == []:
                 word = u"".join(wordbuffer)
                 words.append(SodaInt(a.fromint(j)))
                 words.append(SodaString(word))
                 wordbuffer = []
                 j += 1
             chars.append(SodaInt(a.fromint(i)))
             chars.append(SodaString(char))
             i += 1
         else:
             chars.append(SodaInt(a.fromint(i)))
             chars.append(SodaString(char))
             wordbuffer.append(char)
             linebuffer.append(char)
             i += 1
     if not wordbuffer == []:
         word = u"".join(wordbuffer)
         words.append(SodaInt(a.fromint(j)))
         words.append(SodaString(word))
     if not linebuffer == []:
         line = u"".join(linebuffer)
         lines.append(SodaInt(a.fromint(k)))
         lines.append(SodaString(line))
     self.textarrays.append(SodaArray(chars))
     self.textarrays.append(SodaArray(words))
     self.textarrays.append(SodaArray(lines))
Example #8
0
def number_number(s):
    sourcepos = s[0].getsourcepos()
    package = fetcher.packages[sourcepos.idx]
    line = str(sourcepos.lineno)
    col = str(sourcepos.colno)
    try:
        a = rbigint()
        return ast.Integer(a.fromstr(s[0].getstr()), package, line, col)
    except Exception:
        package = fetcher.packages[s[0].getsourcepos().idx]
        line = str(s[0].getsourcepos().lineno)
        col = str(s[0].getsourcepos().colno)
        msg = "error in number %s" % s[0].getstr()
        sodaError(package, line, col, msg)
Example #9
0
 def evaluate_args(self, argstack):
     argstack.reverse()
     if self.isvariadic:
         a = rbigint()
         enumlist = []
         nargstack = []
         j = 0
         for i in range(self.arity - 1, len(argstack)):
             enumlist.append(SodaInt(a.fromint(j)))
             enumlist.append(argstack[i])
             j += 1
         for k in range(0, self.arity - 1):
             nargstack.append(argstack[k])
         argstack = nargstack
         argstack.append(SodaArray(enumlist))
     for i in range(0, len(self.compiler.constants)):
         self.constbuffer.append(self.compiler.constants[i])
         if isinstance(self.compiler.constants[i], SodaDummy):
             self.compiler.constants[i] = argstack.pop()
Example #10
0
def _rbigint_maskoff_high(value, masklen):
    if not value.sign: return value
    # assert value.sign > 0

    lastword = (masklen - 1) / SHIFT
    masksize = lastword + 1
    if masksize > value.numdigits(): return value
    assert masksize > 0  # tell the dumb translator
    # From now on 0 < masksize <= value.numdigits(), so lastword exists

    ret = rbigint(value._digits[:masksize], 1, masksize)

    # Here, if masklen % SHIFT == 0, then we don't need to mask the last
    # word because wordpos = masklen / SHIFT = masksize in this case
    maskbit = masklen % SHIFT
    if maskbit != 0:
        lastdigit = ret.digit(lastword)
        mask = get_int_mask(maskbit)
        if lastdigit >= mask:
            ret.setdigit(lastword, lastdigit & mask)

    ret._normalize()
    return ret
Example #11
0
def _rbigint_rshift_maskoff(value, shamt, masklen):
    if not value.sign: return value
    # shamt must be > 0, value.sign must > 0
    if shamt == 0: return _rbigint_maskoff_high(value, masklen)

    wordshift = shamt / SHIFT
    oldsize = value.numdigits()
    if oldsize <= wordshift: return NULLRBIGINT

    newsize = oldsize - wordshift
    masksize = (masklen - 1) / SHIFT + 1
    retsize = min(newsize, masksize)

    loshift = shamt - wordshift * SHIFT
    hishift = SHIFT - loshift
    ret = rbigint([NULLDIGIT] * retsize, 1, retsize)
    i = 0
    while i < retsize:
        newdigit = (value.digit(wordshift) >> loshift)
        if i + 1 < newsize:
            newdigit |= (value.digit(wordshift + 1) << hishift)
        ret.setdigit(i, newdigit)
        i += 1
        wordshift += 1

    if masksize <= retsize:
        maskbit = masklen % SHIFT
        if maskbit != 0:
            lastword = i - 1
            lastdigit = ret.digit(lastword)
            mask = get_int_mask(maskbit)
            if lastdigit >= mask:
                ret.setdigit(lastword, lastdigit & mask)

    ret._normalize()
    return ret
Example #12
0
def bigint(lst, sign):
    for digit in lst:
        assert digit & MASK == digit    # wrongly written test!
    return rbigint(map(_store_digit, map(_mask_digit, lst)), sign)
Example #13
0
 def fromdecimalstr(s):
     return rbigint(s)
Example #14
0
 def fromint(i):
     return rbigint(i)
Example #15
0
 def __init__(self, value):
     assert isinstance(value, unicode)
     self.value = value
     a = rbigint()
     self.length = SodaInt(a.fromint(len(self.value)))
Example #16
0
 def toint(self):
     a = rbigint()
     number = a.fromstr(str(self.value.build()))
     return SodaInt(number)
Example #17
0
def _rbigint_lshift_maskoff(value, shamt, masklen):
    if not value.sign or not shamt: return value
    if shamt >= masklen: return NULLRBIGINT
    assert shamt > 0
    # shamt must > 0, value.sign must >= 0

    wordshift = shamt // SHIFT
    remshift = shamt - wordshift * SHIFT

    oldsize = value.numdigits()

    maskbit = masklen % SHIFT
    masksize = (masklen - 1) / SHIFT + 1

    if not remshift:
        retsize = min(oldsize + wordshift, masksize)
        ret = rbigint([NULLDIGIT] * retsize, 1, retsize)
        j = 0
        while j < oldsize and wordshift < retsize:
            ret.setdigit(wordshift, value.digit(j))
            wordshift += 1
            j += 1

        if wordshift == masksize and maskbit != 0:
            lastword = retsize - 1
            ret.setdigit(lastword, ret.digit(lastword) & get_int_mask(maskbit))

        ret._normalize()
        return ret

    newsize = oldsize + wordshift + 1

    if masksize < newsize:
        retsize = masksize

        ret = rbigint([NULLDIGIT] * retsize, 1, retsize)
        accum = _widen_digit(0)
        j = 0
        while j < oldsize and wordshift < retsize:
            accum += value.widedigit(j) << remshift
            ret.setdigit(wordshift, accum)
            accum >>= SHIFT
            wordshift += 1
            j += 1

        # no accum
        if maskbit != 0:
            lastword = retsize - 1
            lastdigit = ret.digit(lastword)
            mask = get_int_mask(maskbit)
            if lastdigit >= mask:
                ret.setdigit(lastword, lastdigit & mask)

        ret._normalize()
        return ret

    # masksize >= newsize
    retsize = newsize

    ret = rbigint([NULLDIGIT] * retsize, 1, retsize)
    accum = _widen_digit(0)
    j = 0
    while j < oldsize and wordshift < retsize:
        accum += value.widedigit(j) << remshift
        ret.setdigit(wordshift, accum)
        accum >>= SHIFT
        wordshift += 1
        j += 1

    if masksize == newsize and maskbit != 0:
        accum &= get_int_mask(maskbit)

    ret.setdigit(wordshift, accum)

    ret._normalize()
    return ret
Example #18
0
 def setval(self, idx, value):
     self.value[idx.str()] = value
     self.keys.append(idx)
     a = rbigint()
     self.length = SodaInt(a.fromint(len(self.value)))
Example #19
0
# Date   : March 10, 2020

from rpython.rlib import jit
from rpython.rlib.rbigint import rbigint, SHIFT, NULLDIGIT, ONERBIGINT, \
                                 NULLRBIGINT, _store_digit, _x_int_sub, \
                                 _widen_digit, BASE16

BASE2 = '01'

# NOTE that we should keep self.value positive after any computation:
# - The sign of the rbigint field should always be one
# - Always AND integer value with mask, never store any negative int
# * Performing rbigint.and_/rbigint.int_and_ will turn sign back to 1
# - rbigint._normalize() can only be called in @jit.elidable funcs

mask = rbigint([NULLDIGIT], 1, 1)
LONG_MASKS = [mask]
for i in xrange(1024):
    mask = mask.int_mul(2).int_add(1)
    LONG_MASKS.append(mask)


def get_long_mask(i):
    return LONG_MASKS[i]


get_long_mask._always_inline_ = True


def get_long_lower(i):
    return LONG_MASKS[i - 1].int_add(1).neg()
Example #20
0
def gcd(u, v):
    from rpython.rlib.rbigint import _v_isub, _v_rshift, SHIFT
    # binary gcd from https://en.wikipedia.org/wiki/Binary_GCD_algorithm
    if not u.tobool():
        return v.abs()
    if not v.tobool():
        return u.abs()

    # The result is negative iff both inputs have a common -1 factor
    if v.sign == -1 and u.sign == -1:
        sign = -1
    else:
        sign = 1

    if u.size == 1 and v.size == 1:
        result = gcd1(u.digit(0), v.digit(0))
        return rbigint([result], sign, 1)

    # Compute the factors of 2 for u and v and record the number of
    # common 2 factors in shift.
    shiftu = count_trailing_zeros(u)
    shiftv = count_trailing_zeros(v)
    shift  = min(shiftu, shiftv)

    # Perform shift on each number, but guarantee that we will end up with a new
    # digit array for each rbigint. They will be mutated
    if shiftu:
        u = u.rshift(shiftu, dont_invert=True)
        if u.sign == -1:
            u.sign = 1
    else:
        u = rbigint(u._digits[:], 1, u.numdigits())

    if shiftv:
        v = v.rshift(shiftv, dont_invert=True)
        if v.sign == -1:
            v.sign = 1
    else:
        v = rbigint(v._digits[:], 1, v.numdigits())

    # From here on, u is always odd.
    while True:

        if u.size == 1 and v.size == 1:
            digit = gcd1(u.digit(0), v.digit(0))
            u = rbigint([digit], 1, 1)
            break

        # Now u and v are both odd. Swap if necessary so u <= v,
        # then set v = v - u (which is even).
        if u.gt(v):
            u, v, = v, u

        assert _v_isub(v, 0, v.numdigits(), u, u.numdigits()) == 0
        v._normalize()

        if not v.tobool():
            break

        # remove all factors of 2 in v -- they are not common
        # note: v is not zero, so while will terminate
        # XXX: Better to perform multiple inplace shifts, or one
        # shift which allocates a new array?
        rshift = count_trailing_zeros(v)
        while rshift >= SHIFT:
            assert _v_rshift(v, v, v.numdigits(), SHIFT - 1) == 0
            rshift -= SHIFT - 1
        assert _v_rshift(v, v, v.numdigits(), rshift) == 0
        v._normalize()

    # restore common factors of 2 and sign
    result = u.lshift(shift)
    result.sign = sign
    return result
Example #21
0
def read_bytearray_bits_impl(space, w_arr, w_addr, w_nbytes):
    # We directly manipulate bytearray here
    assert isinstance(w_arr, W_BytearrayObject)
    ba_data = w_arr._data
    ba_len = len(ba_data)
    ba_offset = w_arr._offset

    nbytes = 0
    if isinstance(w_nbytes, W_SmallBits):
        nbytes = w_nbytes.intval
    elif type(w_nbytes) is W_IntObject:
        nbytes = w_nbytes.intval
    elif isinstance(w_nbytes, W_BigBits):
        tmp = w_nbytes.bigval
        if tmp.numdigits() > 1:
            raise oefmt(space.w_ValueError,
                        "nbytes [%s] too big for bytearray read Bits%d",
                        rbigint.str(tmp), w_nbytes.nbits)
        nbytes = tmp.digit(0)
    elif type(w_nbytes) is W_LongObject:
        nbytes = w_nbytes.num.toint()
    else:
        raise oefmt(space.w_TypeError, "Please pass in int/Bits")

    addr = 0
    if isinstance(w_addr, W_SmallBits):
        addr = w_addr.intval
    elif type(w_addr) is W_IntObject:
        addr = w_addr.intval
    elif isinstance(w_addr, W_BigBits):
        tmp = w_addr.bigval
        if tmp.numdigits() > 1:
            raise oefmt(space.w_ValueError,
                        "Index [%s] too big for bytearray read Bits%d",
                        rbigint.str(tmp), w_addr.nbits)
        addr = tmp.digit(0)
    elif type(w_addr) is W_LongObject:
        addr = w_addr.num.toint()
    else:
        raise oefmt(space.w_TypeError, "Please pass in int/Bits")

    if addr < 0:
        raise oefmt(space.w_ValueError,
                    "read_bytearray_bits only accept positive addr.")

    begin = addr + ba_offset
    end = begin + nbytes

    if end > ba_len:
        raise OperationError(space.w_IndexError,
                             space.newtext("bytearray index out of range"))

    if nbytes < 8:
        intval = 0
        while end > begin:
            end -= 1
            intval = (intval << 8) + ord(ba_data[end])

        return W_SmallBits(nbytes << 3, intval)

    else:
        digits = []
        current_word = 0
        bitstart = 0

        while begin < end:
            item = ord(ba_data[begin])

            bitend = bitstart + 8

            if bitend <= SHIFT:  # we are good
                current_word |= item << bitstart
                bitstart = bitend
            else:
                bitend -= SHIFT
                this_nbits = 8 - bitend
                current_word |= (item & get_int_mask(this_nbits)) << bitstart
                digits.append(_store_digit(current_word))

                current_word = item >> this_nbits
                bitstart = 8 - this_nbits

            begin += 1

        digits.append(_store_digit(current_word))

        bigval = rbigint(digits[:], sign=1)  # 1 is positive!!!
        bigval._normalize()

        return W_BigBits(nbytes << 3, bigval)
Example #22
0
def setitem_long_int_helper(value, other, start, stop):
    vsize = value.numdigits()
    if other < 0:
        slice_nbits = stop - start
        if slice_nbits < SHIFT:
            other &= get_int_mask(slice_nbits)
        else:
            tmp = get_long_mask(slice_nbits).int_and_(other)
            return setitem_long_long_helper(value, tmp, start, stop)

    # wordstart must < wordstop
    wordstart = start / SHIFT
    bitstart = start - wordstart * SHIFT

    # vsize <= wordstart < wordstop, concatenate
    if wordstart >= vsize:
        if not other: return value  # if other is zero, do nothing

        if not bitstart:  # aha, not chopped into two parts
            return rbigint( value._digits[:vsize] + \
                            [NULLDIGIT]*(wordstart-vsize) + \
                            [_store_digit(other)], 1, wordstart+1 )

        # split into two parts
        lo = SHIFT - bitstart
        val1 = other & get_int_mask(lo)
        if val1 == other:  # aha, the higher part is zero
            return rbigint( value._digits[:vsize] + \
                            [NULLDIGIT]*(wordstart-vsize) + \
                            [_store_digit(val1 << bitstart)], 1, wordstart+1 )
        return rbigint( value._digits[:vsize] + \
                        [NULLDIGIT]*(wordstart-vsize) + \
                        [_store_digit(val1 << bitstart)] + \
                        [_store_digit(other >> lo)], 1, wordstart+2 )

    wordstop = stop / SHIFT
    bitstop = stop - wordstop * SHIFT
    # (wordstart <=) wordstop < vsize
    if wordstop < vsize:
        ret = rbigint(value._digits[:vsize], 1, vsize)
        maskstop = get_int_mask(bitstop)
        valstop = ret.digit(wordstop)

        if wordstop == wordstart:  # valstop is ret.digit(wordstart)
            valuemask = ~(maskstop - get_int_mask(bitstart))
            ret.setdigit(wordstop, (valstop & valuemask) | (other << bitstart))

        # span multiple words
        # wordstart < wordstop
        else:
            # do start
            if not bitstart:
                ret.setdigit(wordstart, other)
                i = wordstart + 1
                while i < wordstop:
                    ret._digits[i] = NULLDIGIT
                    i += 1
                ret.setdigit(wordstop, valstop & ~maskstop)
            else:
                lo = SHIFT - bitstart
                val1 = other & get_int_mask(lo)
                word = (ret.digit(wordstart)
                        & get_int_mask(bitstart)) | (val1 << bitstart)
                ret.setdigit(wordstart, word)

                val2 = other >> lo
                i = wordstart + 1
                if i == wordstop:
                    ret.setdigit(i, val2 | (valstop & ~maskstop))
                else:  # i < wordstop
                    ret.setdigit(i, val2)
                    i += 1
                    while i < wordstop:
                        ret._digits[i] = NULLDIGIT
                        i += 1
                    ret.setdigit(wordstop, valstop & ~maskstop)
        ret._normalize()
        return ret

    # wordstart < vsize <= wordstop, highest bits will be cleared
    newsize = wordstart + 2  #
    assert wordstart >= 0
    ret = rbigint( value._digits[:wordstart] + \
                  [NULLDIGIT, NULLDIGIT], 1, newsize )

    bitstart = start - wordstart * SHIFT
    if not bitstart:
        ret.setdigit(wordstart, other)
    else:
        lo = SHIFT - bitstart
        val1 = other & get_int_mask(lo)
        word = (value.digit(wordstart)
                & get_int_mask(bitstart)) | (val1 << bitstart)
        ret.setdigit(wordstart, word)

        if val1 != other:
            ret.setdigit(wordstart + 1, other >> lo)

    ret._normalize()
    return ret
Example #23
0
def setitem_long_long_helper(value, other, start, stop):
    if other.numdigits() <= 1:
        return setitem_long_int_helper(value, other.digit(0), start, stop)

    if other.sign < 0:
        other = other.and_(get_long_mask(stop - start))
        if other.numdigits() == 1:
            return setitem_long_int_helper(value, other.digit(0), start, stop)

    vsize = value.numdigits()
    other = other.lshift(start)  # lshift first to align two rbigints
    osize = other.numdigits()

    # After the two above checks, we have made sure other has more than one digit
    # assert osize >= 2
    # assert wordstart < wordstop

    # Also, the caller must have already checked if bitwidth exceeds the slice
    # assert wordstart <= osize - 1 <= wordstop

    wordstart = start / SHIFT

    # 1. vsize <= wordstart < wordstop, concatenate
    if vsize <= wordstart:
        return rbigint(value._digits[:vsize] + other._digits[vsize:], 1, osize)

    bitstart = start - wordstart * SHIFT

    wordstop = stop / SHIFT

    # 2. wordstart < vsize <= wordstop, merge wordstart and concatenate
    if vsize <= wordstop:
        assert wordstart >= 0
        ret = rbigint( value._digits[:wordstart] + \
                       other._digits[wordstart:osize], 1, osize )

        # union start, there is no value in lower bits of other.digit(wordstart)
        if bitstart:
            value_lo = value.digit(wordstart) & get_int_mask(bitstart)  # lo
            ret.setdigit(wordstart, value_lo | ret.digit(wordstart))  # lo | hi

        return ret

    # 3. wordstart < wordstop < vsize, handle both sides
    ret = rbigint(value._digits[:], 1, vsize)

    # union start, there is no value in lower bits of other.digit(wordstart)
    value_lo = ret.digit(wordstart) & get_int_mask(bitstart)  # lo
    ret.setdigit(wordstart, value_lo | other.digit(wordstart))  # lo | hi

    # put other into
    i = wordstart + 1

    inv_maskstop = ~get_int_mask(stop - wordstop * SHIFT)
    # wordstop == osize - 1 means other's last word is wordstop
    if wordstop == osize - 1:
        while i < wordstop:
            ret.setdigit(i, other.digit(i))
            i += 1
        # union stop
        value_hi = ret.digit(wordstop) & inv_maskstop  # hi
        ret.setdigit(wordstop, other.digit(wordstop) | value_hi)  # lo|hi

    # wordstop > osize - 1, other is shorter
    else:
        while i < osize:
            ret.setdigit(i, other.digit(i))
            i += 1
        while i < wordstop:
            ret._digits[i] = NULLDIGIT
            i += 1

        # clear stop
        ret.setdigit(wordstop, ret.digit(wordstop) & inv_maskstop)

    ret._normalize()
    return ret