math/big: removed TODO, cleanups

- factor out handling of sign
- rename bstring, pstring to fmtB, fmtP consistent with fmtE, fmtF
- move all float-to-string conversion functions into ftoa.go
- no functional changes

Change-Id: I5970ecb874dc9c387630b59147d90bda16a5d8e6
Reviewed-on: https://go-review.googlesource.com/10387
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
index 5ab75e9..dc62b45 100644
--- a/src/math/big/floatconv.go
+++ b/src/math/big/floatconv.go
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file implements float-to-string conversion functions.
+// This file implements string-to-Float conversion functions.
 
 package big
 
 import (
 	"fmt"
 	"io"
-	"strconv"
 	"strings"
 )
 
@@ -244,136 +243,3 @@
 func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
 	return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
 }
-
-// Format converts the floating-point number x to a string according
-// to the given format and precision prec. The format is one of:
-//
-//	'e'	-d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
-//	'E'	-d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
-//	'f'	-ddddd.dddd, no exponent
-//	'g'	like 'e' for large exponents, like 'f' otherwise
-//	'G'	like 'E' for large exponents, like 'f' otherwise
-//	'b'	-ddddddp±dd, binary exponent
-//	'p'	-0x.dddp±dd, binary exponent, hexadecimal mantissa
-//
-// For the binary exponent formats, the mantissa is printed in normalized form:
-//
-//	'b'	decimal integer mantissa using x.Prec() bits, or -0
-//	'p'	hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
-//
-// The precision prec controls the number of digits (excluding the exponent)
-// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
-// it is the number of digits after the decimal point. For 'g' and 'G' it is
-// the total number of digits. A negative precision selects the smallest
-// number of digits necessary such that ParseFloat will return f exactly.
-// The prec value is ignored for the 'b' or 'p' format.
-//
-// BUG(gri) Float.Format does not accept negative precisions.
-// BUG(gri) The Float.Format signature conflicts with Format(f fmt.State, c rune).
-//          (https://github.com/golang/go/issues/10938)
-func (x *Float) Format(format byte, prec int) string {
-	const extra = 10 // TODO(gri) determine a good/better value 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 {
-	// TODO(gri) factor out handling of sign?
-
-	// Inf
-	if x.IsInf() {
-		var ch byte = '+'
-		if x.neg {
-			ch = '-'
-		}
-		buf = append(buf, ch)
-		return append(buf, "Inf"...)
-	}
-
-	// easy formats
-	switch format {
-	case 'b':
-		return x.bstring(buf)
-	case 'p':
-		return x.pstring(buf)
-	}
-
-	return x.bigFtoa(buf, format, prec)
-}
-
-// BUG(gri): Float.String uses x.Format('g', 10) rather than x.Format('g', -1).
-func (x *Float) String() string {
-	return x.Format('g', 10)
-}
-
-// 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.Prec() bits in binary
-// representation.
-func (x *Float) bstring(buf []byte) []byte {
-	if x.neg {
-		buf = append(buf, '-')
-	}
-	if x.form == zero {
-		return append(buf, '0')
-	}
-
-	if debugFloat && x.form != finite {
-		panic("non-finite float")
-	}
-	// x != 0
-
-	// adjust mantissa to use exactly x.prec bits
-	m := x.mant
-	switch w := uint32(len(x.mant)) * _W; {
-	case w < x.prec:
-		m = nat(nil).shl(m, uint(x.prec-w))
-	case w > x.prec:
-		m = nat(nil).shr(m, uint(w-x.prec))
-	}
-
-	buf = append(buf, m.decimalString()...)
-	buf = append(buf, 'p')
-	e := int64(x.exp) - int64(x.prec)
-	if e >= 0 {
-		buf = append(buf, '+')
-	}
-	return strconv.AppendInt(buf, e, 10)
-}
-
-// 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(buf []byte) []byte {
-	if x.neg {
-		buf = append(buf, '-')
-	}
-	if x.form == zero {
-		return append(buf, '0')
-	}
-
-	if debugFloat && x.form != finite {
-		panic("non-finite float")
-	}
-	// x != 0
-
-	// remove trailing 0 words early
-	// (no need to convert to hex 0's and trim later)
-	m := x.mant
-	i := 0
-	for i < len(m) && m[i] == 0 {
-		i++
-	}
-	m = m[i:]
-
-	buf = append(buf, "0x."...)
-	buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
-	buf = append(buf, 'p')
-	if x.exp >= 0 {
-		buf = append(buf, '+')
-	}
-	return strconv.AppendInt(buf, int64(x.exp), 10)
-}
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
index 6ba1575..db30031 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -366,6 +366,7 @@
 
 		// unsupported format
 		{"3.14", 64, 'x', 0, "%x"},
+		{"-3.14", 64, 'x', 0, "%x"},
 	} {
 		f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
 		if err != nil {
diff --git a/src/math/big/ftoa.go b/src/math/big/ftoa.go
index 0a9edfd..0f943e1 100644
--- a/src/math/big/ftoa.go
+++ b/src/math/big/ftoa.go
@@ -2,34 +2,89 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file implements the 'e', 'f', 'g' floating-point formats.
-// It is closely following the corresponding implementation in
-// strconv/ftoa.go, but modified and simplified for big.Float.
-
-// Algorithm:
-//   1) convert Float to multiprecision decimal
-//   2) round to desired precision
-//   3) read digits out and format
+// This file implements Float-to-string conversion functions.
+// It is closely following the corresponding implementation
+// in strconv/ftoa.go, but modified and simplified for Float.
 
 package big
 
-import "strconv"
+import (
+	"strconv"
+	"strings"
+)
 
-// TODO(gri) Consider moving sign into decimal - could make the signatures below cleaner.
+// Format converts the floating-point number x to a string according
+// to the given format and precision prec. The format is one of:
+//
+//	'e'	-d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
+//	'E'	-d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
+//	'f'	-ddddd.dddd, no exponent
+//	'g'	like 'e' for large exponents, like 'f' otherwise
+//	'G'	like 'E' for large exponents, like 'f' otherwise
+//	'b'	-ddddddp±dd, binary exponent
+//	'p'	-0x.dddp±dd, binary exponent, hexadecimal mantissa
+//
+// For the binary exponent formats, the mantissa is printed in normalized form:
+//
+//	'b'	decimal integer mantissa using x.Prec() bits, or -0
+//	'p'	hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
+//
+// The precision prec controls the number of digits (excluding the exponent)
+// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
+// it is the number of digits after the decimal point. For 'g' and 'G' it is
+// the total number of digits. A negative precision selects the smallest
+// number of digits necessary such that ParseFloat will return f exactly.
+// The prec value is ignored for the 'b' or 'p' format.
+//
+// BUG(gri) Float.Format does not accept negative precisions.
+// BUG(gri) The Float.Format signature conflicts with Format(f fmt.State, c rune).
+//          (https://github.com/golang/go/issues/10938)
+func (x *Float) Format(format byte, prec int) string {
+	const extra = 10 // TODO(gri) determine a good/better value here
+	return string(x.Append(make([]byte, 0, prec+extra), format, prec))
+}
 
-// bigFtoa formats a float for the %e, %E, %f, %g, and %G formats.
-func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
-	if debugFloat && f.IsInf() {
-		panic("non-finite float")
+// String formats x like x.Format('g', 10).
+func (x *Float) String() string {
+	return x.Format('g', 10)
+}
+
+// Append appends to buf the string form of the floating-point number x,
+// as generated by x.Format, and returns the extended buffer.
+func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
+	// sign
+	if x.neg {
+		buf = append(buf, '-')
 	}
 
+	// Inf
+	if x.IsInf() {
+		if !x.neg {
+			buf = append(buf, '+')
+		}
+		return append(buf, "Inf"...)
+	}
+
+	// pick off easy formats
+	switch fmt {
+	case 'b':
+		return x.fmtB(buf)
+	case 'p':
+		return x.fmtP(buf)
+	}
+
+	// Algorithm:
+	//   1) convert Float to multiprecision decimal
+	//   2) round to desired precision
+	//   3) read digits out and format
+
 	// 1) convert Float to multiprecision decimal
 	var mant nat
-	if f.form == finite {
-		mant = f.mant
+	if x.form == finite {
+		mant = x.mant
 	}
 	var d decimal
-	d.init(mant, int(f.exp)-f.mant.bitLen())
+	d.init(mant, int(x.exp)-x.mant.bitLen())
 
 	// 2) round to desired precision
 	shortest := false
@@ -67,9 +122,9 @@
 	// 3) read digits out and format
 	switch fmt {
 	case 'e', 'E':
-		return fmtE(buf, fmt, prec, f.neg, d)
+		return fmtE(buf, fmt, prec, d)
 	case 'f':
-		return fmtF(buf, prec, f.neg, d)
+		return fmtF(buf, prec, d)
 	case 'g', 'G':
 		// trim trailing fractional zeros in %e format
 		eprec := prec
@@ -88,25 +143,23 @@
 			if prec > len(d.mant) {
 				prec = len(d.mant)
 			}
-			return fmtE(buf, fmt+'e'-'g', prec-1, f.neg, d)
+			return fmtE(buf, fmt+'e'-'g', prec-1, d)
 		}
 		if prec > d.exp {
 			prec = len(d.mant)
 		}
-		return fmtF(buf, max(prec-d.exp, 0), f.neg, d)
+		return fmtF(buf, max(prec-d.exp, 0), d)
 	}
 
 	// unknown format
+	if x.neg {
+		buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
+	}
 	return append(buf, '%', fmt)
 }
 
-// %e: -d.ddddde±dd
-func fmtE(buf []byte, fmt byte, prec int, neg bool, d decimal) []byte {
-	// sign
-	if neg {
-		buf = append(buf, '-')
-	}
-
+// %e: d.ddddde±dd
+func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
 	// first digit
 	ch := byte('0')
 	if len(d.mant) > 0 {
@@ -149,13 +202,8 @@
 	return strconv.AppendInt(buf, exp, 10)
 }
 
-// %f: -ddddddd.ddddd
-func fmtF(buf []byte, prec int, neg bool, d decimal) []byte {
-	// sign
-	if neg {
-		buf = append(buf, '-')
-	}
-
+// %f: ddddddd.ddddd
+func fmtF(buf []byte, prec int, d decimal) []byte {
 	// integer, padded with zeros as needed
 	if d.exp > 0 {
 		m := min(len(d.mant), d.exp)
@@ -182,6 +230,73 @@
 	return buf
 }
 
+// fmtB 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.Prec() bits in binary
+// representation.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtB(buf []byte) []byte {
+	if x.form == zero {
+		return append(buf, '0')
+	}
+
+	if debugFloat && x.form != finite {
+		panic("non-finite float")
+	}
+	// x != 0
+
+	// adjust mantissa to use exactly x.prec bits
+	m := x.mant
+	switch w := uint32(len(x.mant)) * _W; {
+	case w < x.prec:
+		m = nat(nil).shl(m, uint(x.prec-w))
+	case w > x.prec:
+		m = nat(nil).shr(m, uint(w-x.prec))
+	}
+
+	buf = append(buf, m.decimalString()...)
+	buf = append(buf, 'p')
+	e := int64(x.exp) - int64(x.prec)
+	if e >= 0 {
+		buf = append(buf, '+')
+	}
+	return strconv.AppendInt(buf, e, 10)
+}
+
+// fmtP 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.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtP(buf []byte) []byte {
+	if x.form == zero {
+		return append(buf, '0')
+	}
+
+	if debugFloat && x.form != finite {
+		panic("non-finite float")
+	}
+	// x != 0
+
+	// remove trailing 0 words early
+	// (no need to convert to hex 0's and trim later)
+	m := x.mant
+	i := 0
+	for i < len(m) && m[i] == 0 {
+		i++
+	}
+	m = m[i:]
+
+	buf = append(buf, "0x."...)
+	buf = append(buf, strings.TrimRight(x.mant.hexString(), "0")...)
+	buf = append(buf, 'p')
+	if x.exp >= 0 {
+		buf = append(buf, '+')
+	}
+	return strconv.AppendInt(buf, int64(x.exp), 10)
+}
+
 func min(x, y int) int {
 	if x < y {
 		return x