correctly rounded floating-point conversions
in new package strconv.

move atoi etc to strconv too.

update fmt, etc to use strconv.

R=r
DELTA=2232  (1691 added, 424 deleted, 117 changed)
OCL=19286
CL=19380
diff --git a/src/lib/fmt/Makefile b/src/lib/fmt/Makefile
index 64ca60c..b9148cc 100644
--- a/src/lib/fmt/Makefile
+++ b/src/lib/fmt/Makefile
@@ -10,15 +10,17 @@
 AS=$(O)a
 AR=$(O)ar
 
-PKG=$(GOROOT)/pkg/fmt.a
+PKG=fmt.a
+PKGDIR=$(GOROOT)/pkg
 
 install: $(PKG)
+	mv $(PKG) $(PKGDIR)/$(PKG)
 
 nuke: clean
-	rm -f $(PKG)
+	rm -f $(PKGDIR)/$(PKG)
 
 clean:
-	rm -f *.$O *.a
+	rm -f *.$O *.a $(PKG)
 
 %.$O: %.go
 	$(GC) $*.go
@@ -39,8 +41,10 @@
 $(PKG): a1 a2
 a1:	$(O1)
 	$(AR) grc $(PKG) $(O1)
+	rm -f $(O1)
 a2:	$(O2)
 	$(AR) grc $(PKG) $(O2)
+	rm -f $(O2)
 
 $(O1): nuke
 $(O2): a1
diff --git a/src/lib/fmt/format.go b/src/lib/fmt/format.go
index 089de43..058c619 100644
--- a/src/lib/fmt/format.go
+++ b/src/lib/fmt/format.go
@@ -4,6 +4,8 @@
 
 package fmt
 
+import "strconv"
+
 /*
 	Raw formatter. See print.go for a more palatable interface.
 
@@ -181,7 +183,7 @@
 	f.clearflags();
 	return f;
 }
-	
+
 func (f *Fmt) d32(a int32) *Fmt {
 	return f.d64(int64(a));
 }
@@ -332,227 +334,82 @@
 	return f;
 }
 
-func pow10(n int) float64 {
-	var d float64;
+// floating-point
 
-	neg := false;
-	if n < 0 {
-		if n < -307 {  // DBL_MIN_10_EXP
-			return 0.;
-		}
-		neg = true;
-		n = -n;
-	}else if n > 308 { // DBL_MAX_10_EXP
-		return 1.79769e+308; // HUGE_VAL
+func Prec(f *Fmt, def int) int {
+	if f.prec_present {
+		return f.prec;
 	}
-
-	if n < NPows10 {
-		d = pows10[n];
-	} else {
-		d = pows10[NPows10-1];
-		for {
-			n -= NPows10 - 1;
-			if n < NPows10 {
-				d *= pows10[n];
-				break;
-			}
-			d *= pows10[NPows10 - 1];
-		}
-	}
-	if neg {
-		return 1/d;
-	}
-	return d;
+	return def;
 }
 
-func unpack(a float64) (negative bool, exp int, num float64) {
-	if a == 0 {
-		return false, 0, 0.0
-	}
-	neg := a < 0;
-	if neg {
-		a = -a;
-	}
-	// find g,e such that a = g*10^e.
-	// guess 10-exponent using 2-exponent, then fine tune.
-	g, e2 := sys.frexp(a);
-	e := int(float64(e2) * .301029995663981);
-	g = a * pow10(-e);
-	for g < 1 {
-		e--;
-		g = a * pow10(-e);
-	}
-	for g >= 10 {
-		e++;
-		g = a * pow10(-e);
-	}
-	return neg, e, g;
-}
-
-// check for Inf, NaN
-func(f *Fmt) InfOrNan(a float64) bool {
-	if sys.isInf(a, 0) {
-		if sys.isInf(a, 1) {
-			f.pad("Inf");
-		} else {
-			f.pad("-Inf");
-		}
-		f.clearflags();
-		return true;
-	}
-	if sys.isNaN(a) {
-		f.pad("NaN");
-		f.clearflags();
-		return true;
-	}
-	return false;
+func FmtString(f *Fmt, s string) *Fmt {
+	f.pad(s);
+	f.clearflags();
+	return f;
 }
 
 // float64
 func (f *Fmt) e64(a float64) *Fmt {
-	var negative bool;
-	var g float64;
-	var exp int;
-	if f.InfOrNan(a) {
-		return f;
-	}
-	negative, exp, g = unpack(a);
-	prec := 6;
-	if f.prec_present {
-		prec = f.prec;
-	}
-	prec++;  // one digit left of decimal
-	var s string;
-	// multiply by 10^prec to get decimal places; put decimal after first digit
-	if g == 0 {
-		// doesn't work for zero - fake it
-		s = "000000000000000000000000000000000000000000000000000000000000";
-		if prec < len(s) {
-			s = s[0:prec];
-		} else {
-			prec = len(s);
-		}
-	} else {
-		g *= pow10(prec);
-		s = f.integer(int64(g + .5), 10, true, &ldigits);  // get the digits into a string
-	}
-	s = s[0:1] + "." + s[1:prec];  // insert a decimal point
-	// print exponent with leading 0 if appropriate.
-	es := New().p(2).integer(int64(exp), 10, true, &ldigits);
-	if exp >= 0 {
-		es = "+" + es;  // TODO: should do this with a fmt flag
-	}
-	s = s + "e" + es;
-	if negative {
-		s = "-" + s;
-	}
-	f.pad(s);
-	f.clearflags();
-	return f;
+	return FmtString(f, strconv.ftoa64(a, 'e', Prec(f, 6)));
 }
 
-// float64
 func (f *Fmt) f64(a float64) *Fmt {
-	var negative bool;
-	var g float64;
-	var exp int;
-	if f.InfOrNan(a) {
-		return f;
-	}
-	negative, exp, g = unpack(a);
-	if exp > 19 || exp < -19 {  // too big for this sloppy code
-		return f.e64(a);
-	}
-	prec := 6;
-	if f.prec_present {
-		prec = f.prec;
-	}
-	// prec is number of digits after decimal point
-	s := "NO";
-	if exp >= 0 {
-		g *= pow10(exp);
-		gi := int64(g);
-		s = New().integer(gi, 10, true, &ldigits);
-		s = s + ".";
-		g -= float64(gi);
-		s = s + New().p(prec).integer(int64(g*pow10(prec) + .5), 10, true, &ldigits);
-	} else {
-		g *= pow10(prec + exp);
-		s = "0." + New().p(prec).integer(int64(g + .5), 10, true, &ldigits);
-	}
-	if negative {
-		s = "-" + s;
-	}
-	f.pad(s);
-	f.clearflags();
-	return f;
+	return FmtString(f, strconv.ftoa64(a, 'f', Prec(f, 6)));
 }
 
-// float64
 func (f *Fmt) g64(a float64) *Fmt {
-	if f.InfOrNan(a) {
-		return f;
-	}
-	f1 := New();
-	f2 := New();
-	if f.wid_present {
-		f1.w(f.wid);
-		f2.w(f.wid);
-	}
-	if f.prec_present {
-		f1.p(f.prec);
-		f2.p(f.prec);
-	}
-	efmt := f1.e64(a).str();
-	ffmt := f2.f64(a).str();
-	// ffmt can return e in my bogus world; don't trim trailing 0s if so.
-	f_is_e := false;
-	for i := 0; i < len(ffmt); i++ {
-		if ffmt[i] == 'e' {
-			f_is_e = true;
-			break;
-		}
-	}
-	if !f_is_e {
-		// strip trailing zeros
-		l := len(ffmt);
-		for ffmt[l-1]=='0' {
-			l--;
-		}
-		ffmt = ffmt[0:l];
-	}
-	if len(efmt) < len(ffmt) {
-		f.pad(efmt);
-	} else {
-		f.pad(ffmt);
-	}
-	f.clearflags();
-	return f;
+	return FmtString(f, strconv.ftoa64(a, 'g', Prec(f, -1)));
+}
+
+func (f *Fmt) fb64(a float64) *Fmt {
+	return FmtString(f, strconv.ftoa64(a, 'b', 0));
+}
+
+// float32
+// cannot defer to float64 versions
+// because it will get rounding wrong in corner cases.
+func (f *Fmt) e32(a float32) *Fmt {
+	return FmtString(f, strconv.ftoa32(a, 'e', Prec(f, -1)));
+}
+
+func (f *Fmt) f32(a float32) *Fmt {
+	return FmtString(f, strconv.ftoa32(a, 'f', Prec(f, 6)));
+}
+
+func (f *Fmt) g32(a float32) *Fmt {
+	return FmtString(f, strconv.ftoa32(a, 'g', Prec(f, -1)));
+}
+
+func (f *Fmt) fb32(a float32) *Fmt {
+	return FmtString(f, strconv.ftoa32(a, 'b', 0));
 }
 
 // float
-func (x *Fmt) f32(a float32) *Fmt {
-	return x.f64(float64(a))
-}
-
 func (x *Fmt) f(a float) *Fmt {
+	if strconv.floatsize == 32 {
+		return x.f32(float32(a))
+	}
 	return x.f64(float64(a))
 }
 
-// float
-func (x *Fmt) e32(a float32) *Fmt {
-	return x.e64(float64(a))
-}
-
 func (x *Fmt) e(a float) *Fmt {
+	if strconv.floatsize == 32 {
+		return x.e32(float32(a))
+	}
 	return x.e64(float64(a))
 }
 
-// float
-func (x *Fmt) g32(a float32) *Fmt {
+func (x *Fmt) g(a float) *Fmt {
+	if strconv.floatsize == 32 {
+		return x.g32(float32(a))
+	}
 	return x.g64(float64(a))
 }
 
-func (x *Fmt) g(a float) *Fmt {
-	return x.g64(float64(a))
+func (x *Fmt) fb(a float) *Fmt {
+	if strconv.floatsize == 32 {
+		return x.fb32(float32(a))
+	}
+	return x.fb64(float64(a))
 }
diff --git a/src/lib/fmt/print.go b/src/lib/fmt/print.go
index 8fa337f..ce7a4f2 100644
--- a/src/lib/fmt/print.go
+++ b/src/lib/fmt/print.go
@@ -230,12 +230,24 @@
 	return "", false;
 }
 
-func getFloat(v reflect.Value) (val float64, ok bool) {
+func getFloat32(v reflect.Value) (val float32, ok bool) {
+	switch v.Kind() {
+	case reflect.Float32Kind:
+		return float32(v.(reflect.Float32Value).Get()), true;
+	case reflect.FloatKind:
+		if v.Type().Size()*8 == 32 {
+			return float32(v.(reflect.FloatValue).Get()), true;
+		}
+	}
+	return 0.0, false;
+}
+
+func getFloat64(v reflect.Value) (val float64, ok bool) {
 	switch v.Kind() {
 	case reflect.FloatKind:
-		return float64(v.(reflect.FloatValue).Get()), true;
-	case reflect.Float32Kind:
-		return float64(v.(reflect.Float32Value).Get()), true;
+		if v.Type().Size()*8 == 64 {
+			return float64(v.(reflect.FloatValue).Get()), true;
+		}
 	case reflect.Float64Kind:
 		return float64(v.(reflect.Float64Value).Get()), true;
 	case reflect.Float80Kind:
@@ -299,9 +311,20 @@
 	case reflect.UintKind, reflect.Uint8Kind, reflect.Uint16Kind, reflect.Uint32Kind, reflect.Uint64Kind:
 		v, signed, ok := getInt(field);
 		s = p.fmt.ud64(uint64(v)).str();
-	case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind, reflect.Float80Kind:
-		v, ok := getFloat(field);
+	case reflect.Float32Kind:
+		v, ok := getFloat32(field);
+		s = p.fmt.g32(v).str();
+	case reflect.Float64Kind, reflect.Float80Kind:
+		v, ok := getFloat64(field);
 		s = p.fmt.g64(v).str();
+	case reflect.FloatKind:
+		if field.Type().Size()*8 == 32 {
+			v, ok := getFloat32(field);
+			s = p.fmt.g32(v).str();
+		} else {
+			v, ok := getFloat64(field);
+			s = p.fmt.g64(v).str();
+		}
 	case reflect.StringKind:
 		v, ok := getString(field);
 		s = p.fmt.s(v).str();
@@ -400,6 +423,10 @@
 			case 'b':
 				if v, signed, ok := getInt(field); ok {
 					s = p.fmt.b64(uint64(v)).str()	// always unsigned
+				} else if v, ok := getFloat32(field); ok {
+					s = p.fmt.fb32(v).str()
+				} else if v, ok := getFloat64(field); ok {
+					s = p.fmt.fb64(v).str()
 				} else {
 					goto badtype
 				}
@@ -442,19 +469,25 @@
 
 			// float
 			case 'e':
-				if v, ok := getFloat(field); ok {
+				if v, ok := getFloat32(field); ok {
+					s = p.fmt.e32(v).str()
+				} else if v, ok := getFloat64(field); ok {
 					s = p.fmt.e64(v).str()
 				} else {
 					goto badtype
 				}
 			case 'f':
-				if v, ok := getFloat(field); ok {
+				if v, ok := getFloat32(field); ok {
+					s = p.fmt.f32(v).str()
+				} else if v, ok := getFloat64(field); ok {
 					s = p.fmt.f64(v).str()
 				} else {
 					goto badtype
 				}
 			case 'g':
-				if v, ok := getFloat(field); ok {
+				if v, ok := getFloat32(field); ok {
+					s = p.fmt.g32(v).str()
+				} else if v, ok := getFloat64(field); ok {
 					s = p.fmt.g64(v).str()
 				} else {
 					goto badtype