essentially 100% coverage of strconv in tests.
fix a few bugs.

R=r
DELTA=294  (275 added, 9 deleted, 10 changed)
OCL=19595
CL=19595
diff --git a/src/lib/strconv/atof.go b/src/lib/strconv/atof.go
index 5f019d3..76b5eba 100644
--- a/src/lib/strconv/atof.go
+++ b/src/lib/strconv/atof.go
@@ -15,6 +15,8 @@
 	"strconv";
 )
 
+package var optimize = true	// can change for testing
+
 // TODO(rsc): Better truncation handling.
 func StringToDecimal(s string) (neg bool, d *Decimal, trunc bool, ok bool) {
 	i := 0;
@@ -182,16 +184,7 @@
 
 	// Denormalized?
 	if mant&(1<<flt.mantbits) == 0 {
-		if exp != flt.bias+1 {
-			// TODO: remove - has no business panicking
-			panicln("DecimalToFloatBits", exp, flt.bias+1);
-		}
-		exp--;
-	} else {
-		if exp <= flt.bias {
-			// TODO: remove - has no business panicking
-			panicln("DecimalToFloatBits1", exp, flt.bias);
-		}
+		exp = flt.bias;
 	}
 	goto out;
 
@@ -327,8 +320,10 @@
 	if !ok {
 		return 0, os.EINVAL;
 	}
-	if f, ok := DecimalToFloat64(neg, d, trunc); ok {
-		return f, nil;
+	if optimize {
+		if f, ok := DecimalToFloat64(neg, d, trunc); ok {
+			return f, nil;
+		}
 	}
 	b, ovf := DecimalToFloatBits(neg, d, trunc, &float64info);
 	f = sys.float64frombits(b);
@@ -343,8 +338,10 @@
 	if !ok {
 		return 0, os.EINVAL;
 	}
-	if f, ok := DecimalToFloat32(neg, d, trunc); ok {
-		return f, nil;
+	if optimize {
+		if f, ok := DecimalToFloat32(neg, d, trunc); ok {
+			return f, nil;
+		}
 	}
 	b, ovf := DecimalToFloatBits(neg, d, trunc, &float32info);
 	f = sys.float32frombits(uint32(b));
diff --git a/src/lib/strconv/decimal.go b/src/lib/strconv/decimal.go
index ee6dd0e..b30c842 100644
--- a/src/lib/strconv/decimal.go
+++ b/src/lib/strconv/decimal.go
@@ -42,6 +42,9 @@
 	buf := new([]byte, n);
 	w := 0;
 	switch {
+	case a.nd == 0:
+		return "0";
+
 	case a.dp <= 0:
 		// zeros fill space between decimal point and digits
 		buf[w] = '0';
@@ -136,10 +139,11 @@
 	for ; n>>k == 0; r++ {
 		if r >= a.nd {
 			if n == 0 {
+				// a == 0; shouldn't get here, but handle anyway.
 				a.nd = 0;
 				return;
 			}
-			for n >> k == 0 {
+			for n>>k == 0 {
 				n = n*10;
 				r++;
 			}
@@ -276,7 +280,7 @@
 
 	if w != 0 {
 		// TODO: Remove - has no business panicking.
-		panic("fmt: bad LeftShift");
+		panicln("strconv: bad LeftShift", w);
 	}
 	a.nd += delta;
 	a.dp += delta;
@@ -287,6 +291,8 @@
 // Returns receiver for convenience.
 func (a *Decimal) Shift(k int) *Decimal {
 	switch {
+	case a.nd == 0:
+		// nothing to do: a == 0
 	case k > 0:
 		for k > MaxShift {
 			LeftShift(a, MaxShift);
diff --git a/src/lib/strconv/ftoa.go b/src/lib/strconv/ftoa.go
index f785c85..5dd057d 100644
--- a/src/lib/strconv/ftoa.go
+++ b/src/lib/strconv/ftoa.go
@@ -144,6 +144,12 @@
 // that will let the original floating point value be precisely
 // reconstructed.  Size is original floating point size (64 or 32).
 func RoundShortest(d *Decimal, mant uint64, exp int, flt *FloatInfo) {
+	// If mantissa is zero, the number is zero; stop now.
+	if mant == 0 {
+		d.nd = 0;
+		return;
+	}
+
 	// TODO: Unless exp == minexp, if the number of digits in d
 	// is less than 17, it seems unlikely that it could not be
 	// the shortest possible number already.  So maybe we can
diff --git a/src/lib/strconv/itoa.go b/src/lib/strconv/itoa.go
index 8cac971..6bf2692 100644
--- a/src/lib/strconv/itoa.go
+++ b/src/lib/strconv/itoa.go
@@ -8,9 +8,9 @@
 	if i == 0 {
 		return "0"
 	}
-	
+
 	neg := false;	// negative
-	u := uint(i);
+	u := uint64(i);
 	if i < 0 {
 		neg = true;
 		u = -u;
@@ -27,7 +27,7 @@
 		bp--;
 		b[bp] = '-'
 	}
-	
+
 	// BUG return string(b[bp:len(b)])
 	return string((&b)[bp:len(b)])
 }
diff --git a/src/lib/strconv/testatof.go b/src/lib/strconv/testatof.go
index 30bc8e9..7ec1670 100644
--- a/src/lib/strconv/testatof.go
+++ b/src/lib/strconv/testatof.go
@@ -16,7 +16,11 @@
 }
 
 var tests = []Test {
+	Test{ "", "0", os.EINVAL },
 	Test{ "1", "1", nil },
+	Test{ "+1", "1", nil },
+	Test{ "1x", "0", os.EINVAL },
+	Test{ "1.1.", "0", os.EINVAL },
 	Test{ "1e23", "1e+23", nil },
 	Test{ "100000000000000000000000", "1e+23", nil },
 	Test{ "1e-100", "1e-100", nil },
@@ -29,6 +33,7 @@
 	Test{ "-1", "-1", nil },
 	Test{ "-0", "0", nil },
 	Test{ "1e-20", "1e-20", nil },
+	Test{ "625e-3", "0.625", nil },
 
 	// largest float64
 	Test{ "1.7976931348623157e308", "1.7976931348623157e+308", nil },
@@ -85,7 +90,9 @@
 	Test{ ".e-1", "0", os.EINVAL },
 }
 
-export func TestAtof() bool {
+func XTestAtof(opt bool) bool {
+	oldopt := strconv.optimize;
+	strconv.optimize = opt;
 	ok := true;
 	for i := 0; i < len(tests); i++ {
 		t := &tests[i];
@@ -96,6 +103,35 @@
 				t.in, out, err, t.out, t.err);
 			ok = false;
 		}
+
+		if float64(float32(out)) == out {
+			out32, err := strconv.atof32(t.in);
+			outs := strconv.ftoa32(out32, 'g', -1);
+			if outs != t.out || err != t.err {
+				fmt.printf("strconv.atof32(%v) = %v, %v want %v, %v  # %v\n",
+					t.in, out32, err, t.out, t.err, out);
+				ok = false;
+			}
+		}
+
+		if floatsize == 64 || float64(float32(out)) == out {
+			outf, err := strconv.atof(t.in);
+			outs := strconv.ftoa(outf, 'g', -1);
+			if outs != t.out || err != t.err {
+				fmt.printf("strconv.ftoa(%v) = %v, %v want %v, %v  # %v\n",
+					t.in, outf, err, t.out, t.err, out);
+				ok = false;
+			}
+		}
 	}
+	strconv.optimize = oldopt;
 	return ok;
 }
+
+export func TestAtof() bool {
+	return XTestAtof(true);
+}
+
+export func TestAtofSlow() bool {
+	return XTestAtof(false);
+}
diff --git a/src/lib/strconv/testatoi.go b/src/lib/strconv/testatoi.go
index 7ffd201..b318fc7 100644
--- a/src/lib/strconv/testatoi.go
+++ b/src/lib/strconv/testatoi.go
@@ -16,6 +16,7 @@
 }
 
 var uint64tests = []Uint64Test {
+	Uint64Test{ "", 0, os.EINVAL },
 	Uint64Test{ "0", 0, nil },
 	Uint64Test{ "1", 1, nil },
 	Uint64Test{ "12345", 12345, nil },
@@ -24,6 +25,7 @@
 	Uint64Test{ "98765432100", 98765432100, nil },
 	Uint64Test{ "18446744073709551615", 1<<64-1, nil },
 	Uint64Test{ "18446744073709551616", 1<<64-1, os.ERANGE },
+	Uint64Test{ "18446744073709551620", 1<<64-1, os.ERANGE },
 }
 
 type Int64Test struct {
@@ -33,6 +35,7 @@
 }
 
 var int64tests = []Int64Test {
+	Int64Test{ "", 0, os.EINVAL },
 	Int64Test{ "0", 0, nil },
 	Int64Test{ "-0", 0, nil },
 	Int64Test{ "1", 1, nil },
@@ -60,6 +63,7 @@
 }
 
 var uint32tests = []Uint32Test {
+	Uint32Test{ "", 0, os.EINVAL },
 	Uint32Test{ "0", 0, nil },
 	Uint32Test{ "1", 1, nil },
 	Uint32Test{ "12345", 12345, nil },
@@ -77,6 +81,7 @@
 }
 
 var int32tests = []Int32Test {
+	Int32Test{ "", 0, os.EINVAL },
 	Int32Test{ "0", 0, nil },
 	Int32Test{ "-0", 0, nil },
 	Int32Test{ "1", 1, nil },
diff --git a/src/lib/strconv/testdecimal.go b/src/lib/strconv/testdecimal.go
new file mode 100644
index 0000000..767701f
--- /dev/null
+++ b/src/lib/strconv/testdecimal.go
@@ -0,0 +1,128 @@
+// 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.
+
+package strconv
+
+import (
+	"fmt";
+	"strconv"
+)
+
+type ShiftTest struct {
+	i uint64;
+	shift int;
+	out string;
+}
+
+var shifttests = []ShiftTest {
+	ShiftTest{ 0, -100, "0" },
+	ShiftTest{ 0, 100, "0" },
+	ShiftTest{ 1, 100, "1267650600228229401496703205376" },
+	ShiftTest{ 1, -100,
+		"0.00000000000000000000000000000078886090522101180541"
+		"17285652827862296732064351090230047702789306640625" },
+	ShiftTest{ 12345678, 8, "3160493568" },
+	ShiftTest{ 12345678, -8, "48225.3046875" },
+	ShiftTest{ 195312, 9, "99999744" },
+	ShiftTest{ 1953125, 9, "1000000000" },
+}
+
+export func TestDecimalShift() bool {
+	ok := true;
+	for i := 0; i < len(shifttests); i++ {
+		t := &shifttests[i];
+		s := strconv.NewDecimal(t.i).Shift(t.shift).String();
+		if s != t.out {
+			fmt.printf("Decimal %v << %v = %v, want %v\n",
+				t.i, t.shift, s, t.out);
+			ok = false;
+		}
+	}
+	return ok;
+}
+
+type RoundTest struct {
+	i uint64;
+	nd int;
+	down, round, up string;
+	int uint64;
+}
+
+var roundtests = []RoundTest {
+	RoundTest{ 0, 4, "0", "0", "0", 0 },
+	RoundTest{ 12344999, 4, "12340000", "12340000", "12350000", 12340000 },
+	RoundTest{ 12345000, 4, "12340000", "12340000", "12350000", 12340000 },
+	RoundTest{ 12345001, 4, "12340000", "12350000", "12350000", 12350000 },
+	RoundTest{ 23454999, 4, "23450000", "23450000", "23460000", 23450000 },
+	RoundTest{ 23455000, 4, "23450000", "23460000", "23460000", 23460000 },
+	RoundTest{ 23455001, 4, "23450000", "23460000", "23460000", 23460000 },
+
+	RoundTest{ 99994999, 4, "99990000", "99990000", "100000000", 99990000 },
+	RoundTest{ 99995000, 4, "99990000", "100000000", "100000000", 100000000 },
+	RoundTest{ 99999999, 4, "99990000", "100000000", "100000000", 100000000 },
+
+	RoundTest{ 12994999, 4, "12990000", "12990000", "13000000", 12990000 },
+	RoundTest{ 12995000, 4, "12990000", "13000000", "13000000", 13000000 },
+	RoundTest{ 12999999, 4, "12990000", "13000000", "13000000", 13000000 },
+}
+
+export func TestDecimalRound() bool {
+	ok := true;
+	for i := 0; i < len(roundtests); i++ {
+		t := &roundtests[i];
+		s := strconv.NewDecimal(t.i).RoundDown(t.nd).String();
+		if s != t.down {
+			fmt.printf("Decimal %v RoundDown %d = %v, want %v\n",
+				t.i, t.nd, s, t.down);
+			ok = false;
+		}
+		s = strconv.NewDecimal(t.i).Round(t.nd).String();
+		if s != t.round {
+			fmt.printf("Decimal %v Round %d = %v, want %v\n",
+				t.i, t.nd, s, t.down);
+			ok = false;
+		}
+		s = strconv.NewDecimal(t.i).RoundUp(t.nd).String();
+		if s != t.up {
+			fmt.printf("Decimal %v RoundUp %d = %v, want %v\n",
+				t.i, t.nd, s, t.up);
+			ok = false;
+		}
+	}
+	return ok;
+}
+
+type RoundIntTest struct {
+	i uint64;
+	shift int;
+	int uint64;
+}
+
+var roundinttests = []RoundIntTest {
+	RoundIntTest{ 0, 100, 0 },
+	RoundIntTest{ 512, -8, 2 },
+	RoundIntTest{ 513, -8, 2 },
+	RoundIntTest{ 640, -8, 2 },
+	RoundIntTest{ 641, -8, 3 },
+	RoundIntTest{ 384, -8, 2 },
+	RoundIntTest{ 385, -8, 2 },
+	RoundIntTest{ 383, -8, 1 },
+	RoundIntTest{ 1, 100, 1<<64-1 },
+	RoundIntTest{ 1000, 0, 1000 },
+}
+
+export func TestDecimalRoundedInteger() bool {
+	ok := true;
+	for i := 0; i < len(roundinttests); i++ {
+		t := roundinttests[i];
+		// TODO: should be able to use int := here.
+		int1 := strconv.NewDecimal(t.i).Shift(t.shift).RoundedInteger();
+		if int1 != t.int {
+			fmt.printf("Decimal %v >> %v RoundedInteger = %v, want %v\n",
+				t.i, t.shift, int1, t.int);
+			ok = false;
+		}
+	}
+	return ok;
+}
diff --git a/src/lib/strconv/testftoa.go b/src/lib/strconv/testftoa.go
index dc4da7a..390cd8b 100644
--- a/src/lib/strconv/testftoa.go
+++ b/src/lib/strconv/testftoa.go
@@ -12,6 +12,8 @@
 	s string;
 }
 
+func fdiv(a, b float64) float64 { return a / b }	// keep compiler in the dark
+
 // TODO: Should be able to call this tests but it conflicts with testatof.go
 var ftests = []Test {
 	Test{ 1, 'e', 5, "1.00000e+00" },
@@ -66,8 +68,22 @@
 	Test{ 1e23+8.5e6, 'e', -1, "1.0000000000000001e+23" },
 	Test{ 1e23+8.5e6, 'f', -1, "100000000000000010000000" },
 	Test{ 1e23+8.5e6, 'g', -1, "1.0000000000000001e+23" },
-	
+
+	Test{ fdiv(5e-304, 1e20), 'g', -1, "5e-324" },
+	Test{ fdiv(-5e-304, 1e20), 'g', -1, "-5e-324" },
+
 	Test{ 32, 'g', -1, "32" },
+	Test{ 32, 'g', 0, "3e+01" },
+
+	Test{ 100, 'x', -1, "%x" },
+
+	Test{ sys.NaN(), 'g', -1, "NaN" },
+	Test{ -sys.NaN(), 'g', -1, "NaN" },
+	Test{ sys.Inf(0), 'g', -1, "+Inf" },
+	Test{ sys.Inf(-1), 'g', -1,  "-Inf" },
+	Test{ -sys.Inf(0), 'g', -1, "-Inf" },
+
+	Test{ -1, 'b', -1, "-4503599627370496p-52" },
 }
 
 export func TestFtoa() bool {
@@ -82,13 +98,13 @@
 			println("test", t.f, string(t.fmt), t.prec, "want", t.s, "got", s);
 			ok = false;
 		}
-		if float64(float32(t.f)) == t.f {
+		if float64(float32(t.f)) == t.f && t.fmt != 'b' {
 			s := strconv.ftoa32(float32(t.f), t.fmt, t.prec);
 			if s != t.s {
 				println("test32", t.f, string(t.fmt), t.prec, "want", t.s, "got", s);
 				ok = false;
 			}
-		}	
+		}
 	}
 	return ok;
 }
diff --git a/src/lib/strconv/testitoa.go b/src/lib/strconv/testitoa.go
new file mode 100644
index 0000000..0602643
--- /dev/null
+++ b/src/lib/strconv/testitoa.go
@@ -0,0 +1,80 @@
+// 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.
+
+package strconv
+
+import (
+	"fmt";
+	"os";
+	"strconv";
+)
+
+type Int64Test struct {
+	in int64;
+	out string;
+}
+
+// TODO: should be called int64tests
+
+var xint64tests = []Int64Test {
+	Int64Test{ 0, "0" },
+	Int64Test{ 1, "1" },
+	Int64Test{ -1, "-1" },
+	Int64Test{ 12345678, "12345678" },
+	Int64Test{ -987654321, "-987654321" },
+	Int64Test{ 1<<31-1, "2147483647" },
+	Int64Test{ -1<<31+1, "-2147483647" },
+	Int64Test{ 1<<31, "2147483648" },
+	Int64Test{ -1<<31, "-2147483648" },
+	Int64Test{ 1<<31+1, "2147483649" },
+	Int64Test{ -1<<31-1, "-2147483649" },
+	Int64Test{ 1<<32-1, "4294967295" },
+	Int64Test{ -1<<32+1, "-4294967295" },
+	Int64Test{ 1<<32, "4294967296" },
+	Int64Test{ -1<<32, "-4294967296" },
+	Int64Test{ 1<<32+1, "4294967297" },
+	Int64Test{ -1<<32-1, "-4294967297" },
+	Int64Test{ 1<<50, "1125899906842624" },
+	Int64Test{ 1<<63-1, "9223372036854775807" },
+	Int64Test{ -1<<63+1, "-9223372036854775807" },
+	Int64Test{ -1<<63, "-9223372036854775808" },
+}
+
+export func TestItoa() bool {
+	ok := true;
+	for i := 0; i < len(xint64tests); i++ {
+		t := xint64tests[i];
+		s := strconv.itoa64(t.in);
+		if s != t.out {
+			fmt.printf("strconv.itoa64(%v) = %v want %v\n",
+				t.in, s, t.out);
+			ok = false;
+		}
+		if int64(int(t.in)) == t.in {
+			s := strconv.itoa(int(t.in));
+			if s != t.out {
+				fmt.printf("strconv.itoa(%v) = %v want %v\n",
+					t.in, s, t.out);
+				ok = false;
+			}
+		}
+	}
+	return ok;
+}
+
+// TODO: Use once there is a strconv.uitoa
+type Uint64Test struct {
+	in uint64;
+	out string;
+}
+
+// TODO: should be able to call this uint64tests.
+var xuint64tests = []Uint64Test {
+	Uint64Test{ 1<<63-1, "9223372036854775807" },
+	Uint64Test{ 1<<63, "9223372036854775808" },
+	Uint64Test{ 1<<63+1, "9223372036854775809" },
+	Uint64Test{ 1<<64-2, "18446744073709551614" },
+	Uint64Test{ 1<<64-1, "18446744073709551615" },
+}
+