big: add Div, Mod, Exp, GcdExt and several other fixes.
R=gri, rsc
CC=go-dev
http://go/go-review/1017036
diff --git a/src/pkg/big/nat.go b/src/pkg/big/nat.go
index 62e649b..71f6565 100644
--- a/src/pkg/big/nat.go
+++ b/src/pkg/big/nat.go
@@ -257,6 +257,66 @@
}
+// q = (uIn-r)/v, with 0 <= r < y
+// See Knuth, Volume 2, section 4.3.1, Algorithm D.
+// Preconditions:
+// len(v) >= 2
+// len(uIn) >= 1 + len(vIn)
+func divNN(z, z2, uIn, v []Word) (q, r []Word) {
+ n := len(v);
+ m := len(uIn)-len(v);
+
+ u := makeN(z2, len(uIn)+1, false);
+ qhatv := make([]Word, len(v)+1);
+ q = makeN(z, m+1, false);
+
+ // D1.
+ shift := leadingZeroBits(v[n-1]);
+ shiftLeft(v, v, shift);
+ shiftLeft(u, uIn, shift);
+ u[len(uIn)] = uIn[len(uIn)-1]>>(uint(_W)-uint(shift));
+
+ // D2.
+ for j := m; j >= 0; j-- {
+ // D3.
+ qhat, rhat := divWW_g(u[j+n], u[j+n-1], v[n-1]);
+
+ // x1 | x2 = q̂v_{n-2}
+ x1, x2 := mulWW_g(qhat, v[n-2]);
+ // test if q̂v_{n-2} > br̂ + u_{j+n-2}
+ for greaterThan(x1, x2, rhat, u[j+n-2]) {
+ qhat--;
+ prevRhat := rhat;
+ rhat += v[n-1];
+ // v[n-1] >= 0, so this tests for overflow.
+ if rhat < prevRhat {
+ break;
+ }
+ x1, x2 = mulWW_g(qhat, v[n-2]);
+ }
+
+ // D4.
+ qhatv[len(v)] = mulAddVWW(&qhatv[0], &v[0], qhat, 0, len(v));
+
+ c := subVV(&u[j], &u[j], &qhatv[0], len(qhatv));
+ if c != 0 {
+ c := addVV(&u[j], &u[j], &v[0], len(v));
+ u[j+len(v)] += c;
+ qhat--;
+ }
+
+ q[j] = qhat;
+ }
+
+ q = normN(q);
+ shiftRight(u, u, shift);
+ shiftRight(v, v, shift);
+ r = normN(u);
+
+ return q, r;
+}
+
+
// log2 computes the integer binary logarithm of x.
// The result is the integer n for which 2^n <= x < 2^(n+1).
// If x == 0, the result is -1.
@@ -314,6 +374,10 @@
base = 10;
if n > 0 && s[0] == '0' {
if n > 1 && (s[1] == 'x' || s[1] == 'X') {
+ if n == 2 {
+ // Reject a string which is just '0x' as nonsense.
+ return nil, 0, 0;
+ }
base, i = 16, 2;
} else {
base, i = 8, 1;
@@ -362,9 +426,62 @@
for len(q) > 0 {
i--;
var r Word;
- q, r = divNW(q, q, 10);
+ q, r = divNW(q, q, Word(base));
s[i] = "0123456789abcdef"[r];
}
return string(s[i:len(s)]);
}
+
+
+// leadingZeroBits returns the number of leading zero bits in x.
+func leadingZeroBits(x Word) int {
+ c := 0;
+ if x < 1 << (_W/2) {
+ x <<= _W/2;
+ c = int(_W/2);
+ }
+
+ for i := 0; x != 0; i++ {
+ if x&(1<<(_W-1)) != 0 {
+ return i + c;
+ }
+ x <<= 1;
+ }
+
+ return int(_W);
+}
+
+
+func shiftLeft(dst, src []Word, n int) {
+ if len(src) == 0 {
+ return;
+ }
+
+ ñ := uint(_W) - uint(n);
+ for i := len(src)-1; i >= 1; i-- {
+ dst[i] = src[i]<<uint(n);
+ dst[i] |= src[i-1]>>ñ;
+ }
+ dst[0] = src[0]<<uint(n);
+}
+
+
+func shiftRight(dst, src []Word, n int) {
+ if len(src) == 0 {
+ return;
+ }
+
+ ñ := uint(_W) - uint(n);
+ for i := 0; i < len(src)-1; i++ {
+ dst[i] = src[i]>>uint(n);
+ dst[i] |= src[i+1]<<ñ;
+ }
+ dst[len(src)-1] = src[len(src)-1]>>uint(n);
+}
+
+
+// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
+func greaterThan(x1, x2, y1, y2 Word) bool {
+ return x1 > y1 || x1 == y1 && x2 > y2;
+}