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
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