First cut at a more realistic multi-precision package:
- implemented low-level operations on word vectors
- implemented corresponding amd64 assembly routines for word vector operations
- implemented first set of operations on unsigned integers
- implemented first set of operations on signed integers
- implemented systematic test cases  for each data type

R=rsc
DELTA=1330  (1330 added, 0 deleted, 0 changed)
OCL=33132
CL=33285
diff --git a/src/pkg/big/bigN.go b/src/pkg/big/bigN.go
new file mode 100644
index 0000000..50d73a7
--- /dev/null
+++ b/src/pkg/big/bigN.go
@@ -0,0 +1,315 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains operations on unsigned multi-precision integers.
+// These are the building blocks for the operations on signed integers
+// and rationals.
+
+package big
+
+// An unsigned integer x of the form
+//
+//   x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
+//
+// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
+// with the digits x[i] as the slice elements.
+//
+// A number is normalized if the slice contains no leading 0 digits.
+// During arithmetic operations, denormalized values may occur but are
+// always normalized before returning the final result. The normalized
+// representation of 0 is the empty or nil slice (length = 0).
+
+func normN(z []Word) []Word {
+	i := len(z);
+	for i > 0 && z[i-1] == 0 {
+		i--;
+	}
+	z = z[0 : i];
+	return z;
+}
+
+
+func makeN(z []Word, m int) []Word {
+	if len(z) > m {
+		z = z[0 : m];  // has at least one extra word for a carry, if any
+		return z;  // reuse z
+	}
+	c := 4;  // minimum capacity
+	if m > c {
+		c = m;
+	}
+	return make([]Word, m, c+1);  // +1: extra word for a carry, if any
+}
+
+
+func newN(z []Word, x uint64) []Word {
+	if x == 0 {
+		return nil;  // len == 0
+	}
+
+	// single-digit values
+	if x == uint64(Word(x)) {
+		z = makeN(z, 1);
+		z[0] = Word(x);
+		return z;
+	}
+
+	// compute number of words n required to represent x
+	n := 0;
+	for t := x; t > 0; t >>= _W {
+		n++;
+	}
+
+	// split x into n words
+	z = makeN(z, n);
+	for i := 0; i < n; i++ {
+		z[i] = Word(x & _M);
+		x >>= _W;
+	}
+
+	return z;
+}
+
+
+func setN(z, x []Word) []Word {
+	z = makeN(z, len(x));
+	for i, d := range x {
+		z[i] = d;
+	}
+	return z;
+}
+
+
+func addNN(z, x, y []Word) []Word {
+	m := len(x);
+	n := len(y);
+
+	switch {
+	case m < n:
+		return addNN(z, y, x);
+	case m == 0:
+		// n == 0 because m >= n; result is 0
+		return makeN(z, 0);
+	case n == 0:
+		// result is x
+		return setN(z, x);
+	}
+
+	z = makeN(z, m);
+	c := addVV(&z[0], &x[0], &y[0], n);
+	if m > n {
+		c = addVW(&z[n], &x[n], c, m-n);
+	}
+	if c > 0 {
+		z = z[0 : m+1];
+		z[m] = c;
+	}
+
+	return z;
+}
+
+
+func subNN(z, x, y []Word) []Word {
+	m := len(x);
+	n := len(y);
+
+	switch {
+	case m < n:
+		panic("underflow");
+	case m == 0:
+		// n == 0 because m >= n; result is 0
+		return makeN(z, 0);
+	case n == 0:
+		// result is x
+		return setN(z, x);
+	}
+
+	z = makeN(z, m);
+	c := subVV(&z[0], &x[0], &y[0], n);
+	if m > n {
+		c = subVW(&z[n], &x[n], c, m-n);
+	}
+	if c != 0 {
+		panic("underflow");
+	}
+
+	z = normN(z);
+	return z;
+}
+
+
+func cmpNN(x, y []Word) int {
+	m := len(x);
+	n := len(y);
+	if m != n || m == 0 {
+		return m-n;
+	}
+
+	i := m-1;
+	for i > 0 && x[i] == y[i] {
+		i--;
+	}
+
+	z := 0;
+	switch {
+	case x[i] < y[i]: z = -1;
+	case x[i] > y[i]: z = 1;
+	}
+	return z;
+}
+
+
+func mulNW(z, x []Word, y Word) []Word {
+	m := len(x);
+	switch {
+	case m == 0 || y == 0:
+		return setN(z, nil);  // result is 0
+	case y == 1:
+		return setN(z, x);  // result is x
+	}
+	// m > 0
+	z = makeN(z, m+1);
+	c := mulVW(&z[0], &x[0], y, m);
+	if c > 0 {
+		z = z[0 : m+1];
+		z[m] = c;
+	}
+	return z;
+}
+
+
+func mulNN(z, x, y []Word) []Word {
+	panic("mulNN unimplemented");
+	return z
+}
+
+
+// q = (x-r)/y, with 0 <= r < y
+func divNW(z, x []Word, y Word) (q []Word, r Word) {
+	m := len(x);
+	switch {
+	case y == 0:
+		panic("division by zero");
+	case y == 1:
+		q = setN(z, x);  // result is x
+		return;
+	case m == 0:
+		q = setN(z, nil);  // result is 0
+		return;
+	}
+	// m > 0
+	z = makeN(z, m);
+	r = divWVW(&z[0], 0, &x[0], y, m);
+	q = normN(z);
+	return;
+}
+
+
+// log2 computes the binary logarithm of x.
+// The result is the integer n for which 2^n <= x < 2^(n+1).
+// If x == 0, the result is < 0.
+func log2(x Word) int {
+	n := 0;
+	for ; x > 0; x >>= 1 {
+		n++;
+	}
+	return n-1;
+}
+
+
+// log2N computes the binary logarithm of x.
+// The result is the integer n for which 2^n <= x < 2^(n+1).
+// If x == 0, the result is < 0.
+func log2N(x []Word) int {
+	m := len(x);
+	if m > 0 {
+		return (m-1)*int(_W) + log2(x[m-1]);
+	}
+	return -1;
+}
+
+
+func hexValue(ch byte) int {
+	var d byte;
+	switch {
+	case '0' <= ch && ch <= '9': d = ch - '0';
+	case 'a' <= ch && ch <= 'f': d = ch - 'a' + 10;
+	case 'A' <= ch && ch <= 'F': d = ch - 'A' + 10;
+	default: return -1;
+	}
+	return int(d);
+}
+
+
+// scanN returns the natural number corresponding to the
+// longest possible prefix of s representing a natural number in a
+// given conversion base, the actual conversion base used, and the
+// prefix length. The syntax of natural numbers follows the syntax
+// of unsigned integer literals in Go.
+//
+// If the base argument is 0, the string prefix determines the actual
+// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
+// ``0'' prefix selects base 8. Otherwise the selected base is 10.
+//
+func scanN(z []Word, s string, base int) ([]Word, int, int) {
+	// determine base if necessary
+	i, n := 0, len(s);
+	if base == 0 {
+		base = 10;
+		if n > 0 && s[0] == '0' {
+			if n > 1 && (s[1] == 'x' || s[1] == 'X') {
+				base, i = 16, 2;
+			} else {
+				base, i = 8, 1;
+			}
+		}
+	}
+	if base < 2 || 16 < base {
+		panic("illegal base");
+	}
+
+	// convert string
+	z = makeN(z, len(z));
+	for ; i < n; i++ {
+		d := hexValue(s[i]);
+		if 0 <= d && d < base {
+			panic("scanN needs mulAddVWW");
+		} else {
+			break;
+		}
+	}
+
+	return z, base, i;
+}
+
+
+// string converts x to a string for a given base, with 2 <= base <= 16.
+// TODO(gri) in the style of the other routines, perhaps this should take
+//           a []byte buffer and return it
+func stringN(x []Word, base int) string {
+	if base < 2 || 16 < base {
+		panic("illegal base");
+	}
+
+	if len(x) == 0 {
+		return "0";
+	}
+
+	// allocate buffer for conversion
+	i := (log2N(x) + 1) / log2(Word(base)) + 1;  // +1: round up
+	s := make([]byte, i);
+
+	// don't destroy x
+	q := setN(nil, x);
+
+	// convert
+	for len(q) > 0 {
+		i--;
+		var r Word;
+		q, r = divNW(q, q, 10);
+		s[i] = "0123456789abcdef"[r];
+	};
+
+	return string(s[i : len(s)]);
+}