1
0
mirror of https://github.com/golang/go synced 2024-11-19 21:44:49 -07:00

fmt: fix floating-point padding once and for all

Rewrite formatFloat to be much simpler and clearer and
avoid the tricky interaction with padding.
The issue refers to complex but the problem is just floating-point.
The new tests added were incorrectly formatted before this fix.
Fixes #8064.

LGTM=jscrockett01, rsc
R=rsc, jscrockett01
CC=golang-codereviews
https://golang.org/cl/99420048
This commit is contained in:
Rob Pike 2014-05-21 12:30:43 -07:00
parent f9c6ad9b6b
commit 4464ae280f
2 changed files with 43 additions and 31 deletions

View File

@ -224,6 +224,8 @@ var fmtTests = []struct {
{"%+.3F", float32(-1.0), "-1.000"},
{"%+07.2f", 1.0, "+001.00"},
{"%+07.2f", -1.0, "-001.00"},
{"%+10.2f", +1.0, " +1.00"},
{"%+10.2f", -1.0, " -1.00"},
{"% .3E", -1.0, "-1.000E+00"},
{"% .3e", 1.0, " 1.000e+00"},
{"%+.3g", 0.0, "+0"},
@ -544,6 +546,16 @@ var fmtTests = []struct {
{"%#072o", -1, zeroFill("-", 71, "1")},
{"%#072d", 1, zeroFill("", 72, "1")},
{"%#072d", -1, zeroFill("-", 71, "1")},
// Padding for complex numbers. Has been bad, then fixed, then bad again.
{"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"},
{"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"},
{"%+10.2f", +104.66 - 440.51i, "( +104.66 -440.51i)"},
{"%+10.2f", -104.66 - 440.51i, "( -104.66 -440.51i)"},
{"%+010.2f", +104.66 + 440.51i, "(+000104.66+000440.51i)"},
{"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"},
{"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"},
{"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
}
// zeroFill generates zero-filled strings of the specified width. The length

View File

@ -5,6 +5,7 @@
package fmt
import (
"math"
"strconv"
"unicode/utf8"
)
@ -360,38 +361,37 @@ func doPrec(f *fmt, def int) int {
// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
// We leave one byte at the beginning of f.intbuf for a sign if needed,
// and make it a space, which we might be able to use.
f.intbuf[0] = ' '
slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
// Add a plus sign or space to the floating-point string representation if missing and required.
// The formatted number starts at slice[1].
switch slice[1] {
case '-', '+':
// If we're zero padding, want the sign before the leading zeros.
// Achieve this by writing the sign out and padding the positive number.
if f.zero && f.widPresent && f.wid > len(slice) {
f.buf.WriteByte(slice[1])
f.wid--
f.pad(slice[2:])
return
}
// We're set; drop the leading space.
slice = slice[1:]
default:
// There's no sign, but we might need one.
if f.plus {
f.buf.WriteByte('+')
f.wid--
f.pad(slice[1:])
return
} else if f.space {
// space is already there
// Format number, reserving space for leading + sign if needed.
num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
if num[1] == '-' || num[1] == '+' {
num = num[1:]
} else {
slice = slice[1:]
num[0] = '+'
}
// num is now a signed version of the number.
// If we're zero padding, want the sign before the leading zeros.
// Achieve this by writing the sign out and then padding the unsigned number.
if f.zero && f.widPresent && f.wid > len(num) {
f.buf.WriteByte(num[0])
f.wid--
f.pad(num[1:])
f.wid++ // Restore width; complex numbers will reuse this value for imaginary part.
return
}
f.pad(slice)
// f.space says to replace a leading + with a space.
if f.space && num[0] == '+' {
num[0] = ' '
f.pad(num)
return
}
// Now we know the sign is attached directly to the number, if present at all.
// We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf).
if f.plus || num[0] == '-' || math.IsInf(v, 0) {
f.pad(num)
return
}
// No sign to show and the number is positive; just print the unsigned number.
f.pad(num[1:])
}
// fmt_e64 formats a float64 in the form -1.23e+12.