// For even == true: u0, v1 >= 0 && u1, v0 <= 0
// For even == false: u0, v1 <= 0 && u1, v0 >= 0
// q, r, s, t are temporary variables to avoid allocations in the multiplication.
-func lehmerUpdate(A, B, q, r, s, t *Int, u0, u1, v0, v1 Word, even bool) {
-
- t.abs = t.abs.setWord(u0)
- s.abs = s.abs.setWord(v0)
- t.neg = !even
- s.neg = even
-
- t.Mul(A, t)
- s.Mul(B, s)
-
- r.abs = r.abs.setWord(u1)
- q.abs = q.abs.setWord(v1)
- r.neg = even
- q.neg = !even
-
- r.Mul(A, r)
- q.Mul(B, q)
+func lehmerUpdate(A, B, q, r *Int, u0, u1, v0, v1 Word, even bool) {
+ mulW(q, B, even, v0)
+ mulW(r, A, even, u1)
+ mulW(A, A, !even, u0)
+ mulW(B, B, !even, v1)
+ A.Add(A, q)
+ B.Add(B, r)
+}
- A.Add(t, s)
- B.Add(r, q)
+// mulW sets z = x * (-?)w
+// where the minus sign is present when neg is true.
+func mulW(z, x *Int, neg bool, w Word) {
+ z.abs = z.abs.mulAddWW(x.abs, w, 0)
+ z.neg = x.neg != neg
}
// euclidUpdate performs a single step of the Euclidean GCD algorithm
// if extended is true, it also updates the cosequence Ua, Ub.
-func euclidUpdate(A, B, Ua, Ub, q, r, s, t *Int, extended bool) {
- q, r = q.QuoRem(A, B, r)
-
- *A, *B, *r = *B, *r, *A
+// q and r are used as temporaries; the initial values are ignored.
+func euclidUpdate(A, B, Ua, Ub, q, r *Int, extended bool) (nA, nB, nr, nUa, nUb *Int) {
+ q.QuoRem(A, B, r)
if extended {
- // Ua, Ub = Ub, Ua - q*Ub
- t.Set(Ub)
- s.Mul(Ub, q)
- Ub.Sub(Ua, s)
- Ua.Set(t)
+ // Ua, Ub = Ub, Ua-q*Ub
+ q.Mul(q, Ub)
+ Ua, Ub = Ub, Ua
+ Ub.Sub(Ub, q)
}
+
+ return B, r, A, Ua, Ub
}
// lehmerGCD sets z to the greatest common divisor of a and b,
// temp variables for multiprecision update
q := new(Int)
r := new(Int)
- s := new(Int)
- t := new(Int)
// ensure A >= B
if A.abs.cmp(B.abs) < 0 {
// Simulate the effect of the single-precision steps using the cosequences.
// A = u0*A + v0*B
// B = u1*A + v1*B
- lehmerUpdate(A, B, q, r, s, t, u0, u1, v0, v1, even)
+ lehmerUpdate(A, B, q, r, u0, u1, v0, v1, even)
if extended {
// Ua = u0*Ua + v0*Ub
// Ub = u1*Ua + v1*Ub
- lehmerUpdate(Ua, Ub, q, r, s, t, u0, u1, v0, v1, even)
+ lehmerUpdate(Ua, Ub, q, r, u0, u1, v0, v1, even)
}
} else {
// Single-digit calculations failed to simulate any quotients.
// Do a standard Euclidean step.
- euclidUpdate(A, B, Ua, Ub, q, r, s, t, extended)
+ A, B, r, Ua, Ub = euclidUpdate(A, B, Ua, Ub, q, r, extended)
}
}
// extended Euclidean algorithm base case if B is a single Word
if len(A.abs) > 1 {
// A is longer than a single Word, so one update is needed.
- euclidUpdate(A, B, Ua, Ub, q, r, s, t, extended)
+ A, B, r, Ua, Ub = euclidUpdate(A, B, Ua, Ub, q, r, extended)
}
if len(B.abs) > 0 {
// A and B are both a single Word.
even = !even
}
- t.abs = t.abs.setWord(ua)
- s.abs = s.abs.setWord(va)
- t.neg = !even
- s.neg = even
-
- t.Mul(Ua, t)
- s.Mul(Ub, s)
-
- Ua.Add(t, s)
+ mulW(Ua, Ua, !even, ua)
+ mulW(Ub, Ub, even, va)
+ Ua.Add(Ua, Ub)
} else {
for bWord != 0 {
aWord, bWord = bWord, aWord%bWord
}
if x != nil {
- *x = *Ua
+ x.Set(Ua)
if negA {
x.neg = !x.neg
}
}
- *z = *A
+ z.Set(A)
return z
}