summaryrefslogtreecommitdiff
path: root/libgo/go/math/big/int.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/math/big/int.go')
-rw-r--r--libgo/go/math/big/int.go50
1 files changed, 38 insertions, 12 deletions
diff --git a/libgo/go/math/big/int.go b/libgo/go/math/big/int.go
index 8e52f0ab27b..bf1fa73cce3 100644
--- a/libgo/go/math/big/int.go
+++ b/libgo/go/math/big/int.go
@@ -323,6 +323,8 @@ func (x *Int) Cmp(y *Int) (r int) {
// (-x) cmp y == y
// (-x) cmp (-y) == -(x cmp y)
switch {
+ case x == y:
+ // nothing to do
case x.neg == y.neg:
r = x.abs.cmp(y.abs)
if x.neg {
@@ -466,7 +468,7 @@ func (x *Int) TrailingZeroBits() uint {
// If m == nil or m == 0, z = x**y unless y <= 0 then z = 1. If m > 0, y < 0,
// and x and n are not relatively prime, z is unchanged and nil is returned.
//
-// Modular exponentation of inputs of a particular size is not a
+// Modular exponentiation of inputs of a particular size is not a
// cryptographically constant-time operation.
func (z *Int) Exp(x, y, m *Int) *Int {
// See Knuth, volume 2, section 4.6.3.
@@ -500,18 +502,36 @@ func (z *Int) Exp(x, y, m *Int) *Int {
return z
}
-// GCD sets z to the greatest common divisor of a and b, which both must
-// be > 0, and returns z.
+// GCD sets z to the greatest common divisor of a and b and returns z.
// If x or y are not nil, GCD sets their value such that z = a*x + b*y.
-// If either a or b is <= 0, GCD sets z = x = y = 0.
+// Regardless of the signs of a and b, z is always >= 0.
+// If a == b == 0, GCD sets z = x = y = 0.
+// If a == 0 and b != 0, GCD sets z = |b|, x = 0, y = sign(b) * 1.
+// If a != 0 and b == 0, GCD sets z = |a|, x = sign(a) * 1, y = 0.
func (z *Int) GCD(x, y, a, b *Int) *Int {
- if a.Sign() <= 0 || b.Sign() <= 0 {
- z.SetInt64(0)
+ if len(a.abs) == 0 || len(b.abs) == 0 {
+ lenA, lenB, negA, negB := len(a.abs), len(b.abs), a.neg, b.neg
+ if lenA == 0 {
+ z.Set(b)
+ } else {
+ z.Set(a)
+ }
+ z.neg = false
if x != nil {
- x.SetInt64(0)
+ if lenA == 0 {
+ x.SetUint64(0)
+ } else {
+ x.SetUint64(1)
+ x.neg = negA
+ }
}
if y != nil {
- y.SetInt64(0)
+ if lenB == 0 {
+ y.SetUint64(0)
+ } else {
+ y.SetUint64(1)
+ y.neg = negB
+ }
}
return z
}
@@ -619,7 +639,7 @@ func euclidUpdate(A, B, Ua, Ub, q, r, s, t *Int, extended bool) {
}
// lehmerGCD sets z to the greatest common divisor of a and b,
-// which both must be > 0, and returns z.
+// which both must be != 0, and returns z.
// If x or y are not nil, their values are set such that z = a*x + b*y.
// See Knuth, The Art of Computer Programming, Vol. 2, Section 4.5.2, Algorithm L.
// This implementation uses the improved condition by Collins requiring only one
@@ -631,8 +651,8 @@ func euclidUpdate(A, B, Ua, Ub, q, r, s, t *Int, extended bool) {
func (z *Int) lehmerGCD(x, y, a, b *Int) *Int {
var A, B, Ua, Ub *Int
- A = new(Int).Set(a)
- B = new(Int).Set(b)
+ A = new(Int).Abs(a)
+ B = new(Int).Abs(b)
extended := x != nil || y != nil
@@ -718,7 +738,7 @@ func (z *Int) lehmerGCD(x, y, a, b *Int) *Int {
A.abs[0] = aWord
}
}
-
+ negA := a.neg
if y != nil {
// avoid aliasing b needed in the division below
if y == b {
@@ -728,12 +748,18 @@ func (z *Int) lehmerGCD(x, y, a, b *Int) *Int {
}
// y = (z - a*x)/b
y.Mul(a, Ua) // y can safely alias a
+ if negA {
+ y.neg = !y.neg
+ }
y.Sub(A, y)
y.Div(y, B)
}
if x != nil {
*x = *Ua
+ if negA {
+ x.neg = !x.neg
+ }
}
*z = *A