Esempio n. 1
0
 def test__v_isub(self):
     f1 = bigint([lobj.MASK] + [0] * 9 + [1], 1)
     f2 = bigint([1], 1)
     borrow = lobj._v_isub(f1, 1, len(f1._digits)-1, f2, 1)
     assert borrow == 0
     assert f1.tolong() == (1 << lobj.SHIFT) ** 10 - 1
Esempio n. 2
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