math/big: build Float.Format on top of Float.Append

Change-Id: I444eec24467f827caa5c88a1c5ae5bce92508b98
Reviewed-on: https://go-review.googlesource.com/3750
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/math/big/float.go b/src/math/big/float.go
index 7047a6d..1c3fcb5 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -176,7 +176,7 @@
 	const msb = 1 << (_W - 1)
 	m := len(x.mant)
 	if x.mant[m-1]&msb == 0 {
-		panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.pstring()))
+		panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0)))
 	}
 	if x.prec <= 0 {
 		panic(fmt.Sprintf("invalid precision %d", x.prec))
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index 3281f27..ec67a6d 100644
--- a/src/math/big/float_test.go
+++ b/src/math/big/float_test.go
@@ -205,7 +205,7 @@
 	} {
 		f := new(Float).SetUint64(want)
 		if got := f.Uint64(); got != want {
-			t.Errorf("got %d (%s); want %d", got, f.pstring(), want)
+			t.Errorf("got %d (%s); want %d", got, f.Format('p', 0), want)
 		}
 	}
 }
@@ -227,7 +227,7 @@
 			}
 			f := new(Float).SetInt64(want)
 			if got := f.Int64(); got != want {
-				t.Errorf("got %d (%s); want %d", got, f.pstring(), want)
+				t.Errorf("got %d (%s); want %d", got, f.Format('p', 0), want)
 			}
 		}
 	}
@@ -251,7 +251,7 @@
 			}
 			f := new(Float).SetFloat64(want)
 			if got, _ := f.Float64(); got != want {
-				t.Errorf("got %g (%s); want %g", got, f.pstring(), want)
+				t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
 			}
 		}
 	}
@@ -677,7 +677,7 @@
 		{append([]int{2, 1, 0} /* 7 */, []int{3, 1} /* 10 */ ...), "0x.88p5" /* 17 */},
 	} {
 		f := fromBits(test.bits...)
-		if got := f.pstring(); got != test.want {
+		if got := f.Format('p', 0); got != test.want {
 			t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
 		}
 	}
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
index 06bbdbc..f50a3a5 100644
--- a/src/math/big/floatconv.go
+++ b/src/math/big/floatconv.go
@@ -7,9 +7,9 @@
 package big
 
 import (
-	"bytes"
 	"fmt"
 	"io"
+	"strconv"
 	"strings"
 )
 
@@ -184,13 +184,20 @@
 //
 // BUG(gri) Currently, Format only accepts the 'b' and 'p' format.
 func (x *Float) Format(format byte, prec int) string {
+	const extra = 10 // TODO(gri) determine a good/better vaue here
+	return string(x.Append(make([]byte, 0, prec+extra), format, prec))
+}
+
+// Append appends the string form of the floating-point number x,
+// as generated by x.Format, to buf and returns the extended buffer.
+func (x *Float) Append(buf []byte, format byte, prec int) []byte {
 	switch format {
 	case 'b':
-		return x.bstring()
+		return x.bstring(buf)
 	case 'p':
-		return x.pstring()
+		return x.pstring(buf)
 	}
-	return fmt.Sprintf(`%%!c(%s)`, format, x.pstring())
+	return append(buf, fmt.Sprintf(`%%!c`, format)...)
 }
 
 // BUG(gri): Currently, String uses the 'p' (rather than 'g') format.
@@ -204,17 +211,18 @@
 // (a strconv 'p' formatted float value can only be interpreted correctly
 // if the bias is known; i.e., we must know if it's a 32bit or 64bit number).
 
-// bstring returns x as a string in the format ["-"] mantissa "p" exponent
-// with a decimal mantissa and a binary exponent, or ["-"] "0" if x is zero.
+// bstring appends the string of x in the format ["-"] mantissa "p" exponent
+// with a decimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
+// and returns the extended buffer.
 // The mantissa is normalized such that is uses x.Precision() bits in binary
 // representation.
-func (x *Float) bstring() string {
+func (x *Float) bstring(buf []byte) []byte {
 	// TODO(gri) handle Inf
+	if x.neg {
+		buf = append(buf, '-')
+	}
 	if len(x.mant) == 0 {
-		if x.neg {
-			return "-0"
-		}
-		return "0"
+		return append(buf, '0')
 	}
 	// x != 0
 	// normalize mantissa
@@ -223,34 +231,27 @@
 	if t > 0 {
 		m = nat(nil).shr(m, t)
 	}
-	var buf bytes.Buffer
-	if x.neg {
-		buf.WriteByte('-')
-	}
-	buf.WriteString(m.decimalString())
-	fmt.Fprintf(&buf, "p%d", x.exp)
-	return buf.String()
+	buf = append(buf, m.decimalString()...)
+	buf = append(buf, 'p')
+	return strconv.AppendInt(buf, int64(x.exp), 10)
 }
 
-// pstring returns x as a string in the format ["-"] "0x." mantissa "p" exponent
-// with a hexadecimal mantissa and a binary exponent, or ["-"] "0" if x is zero.
+// pstring appends the string of x in the format ["-"] "0x." mantissa "p" exponent
+// with a hexadecimal mantissa and a binary exponent, or ["-"] "0" if x is zero,
+// ad returns the extended buffer.
 // The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
-func (x *Float) pstring() string {
+func (x *Float) pstring(buf []byte) []byte {
 	// TODO(gri) handle Inf
+	if x.neg {
+		buf = append(buf, '-')
+	}
 	if len(x.mant) == 0 {
-		if x.neg {
-			return "-0"
-		}
-		return "0"
+		return append(buf, '0')
 	}
 	// x != 0
 	// mantissa is stored in normalized form
-	var buf bytes.Buffer
-	if x.neg {
-		buf.WriteByte('-')
-	}
-	buf.WriteString("0x.")
-	buf.WriteString(strings.TrimRight(x.mant.hexString(), "0"))
-	fmt.Fprintf(&buf, "p%d", x.exp)
-	return buf.String()
+	buf = append(buf, "0x."...)
+	buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
+	buf = append(buf, 'p')
+	return strconv.AppendInt(buf, int64(x.exp), 10)
 }