Commit bd6d8428 authored by Martin Möhrmann's avatar Martin Möhrmann Committed by Rob Pike

fmt: refactor and unify float and complex formatting

Removes specialized functions for each verb and float/complex size
and replaces them with generic variants fmtFloat and
fmtComplex similar to other generic fmt functions.

Simplifies the complex formatting by relying on fmtFloat
to handle the verb and default precision selection.

Complex imaginary formatting does not need to clear the f.space flag
because the set f.plus flag will force a sign instead of a space.

Sets default precision for %b to -1 (same as %g and %G)
since precision for %b has no affect in strconv.AppendFloat.

Add more tests and group them a bit better.
Use local copies of +Inf,-Inf and NaN instead
of math package functions for testing.

Saves around 8kb in the go binary.

name              old time/op  new time/op  delta
SprintfFloat-2     200ns ± 4%   196ns ± 4%  -1.55%  (p=0.007 n=20+20)
SprintfComplex-2   569ns ± 4%   570ns ± 3%    ~     (p=0.804 n=20+20)

Change-Id: I36d35dab6f835fc2bd2c042ac97705868eb2446f
Reviewed-on: https://go-review.googlesource.com/20252Reviewed-by: 's avatarRob Pike <r@golang.org>
Run-TryBot: Rob Pike <r@golang.org>
parent 5763476f
...@@ -48,6 +48,12 @@ func TestFmtInterface(t *testing.T) { ...@@ -48,6 +48,12 @@ func TestFmtInterface(t *testing.T) {
} }
} }
var (
NaN = math.NaN()
posInf = math.Inf(1)
negInf = math.Inf(-1)
)
const b32 uint32 = 1<<32 - 1 const b32 uint32 = 1<<32 - 1
const b64 uint64 = 1<<64 - 1 const b64 uint64 = 1<<64 - 1
...@@ -345,9 +351,31 @@ var fmtTests = []struct { ...@@ -345,9 +351,31 @@ var fmtTests = []struct {
{"% .3g", 1.0, " 1"}, {"% .3g", 1.0, " 1"},
{"%b", float32(1.0), "8388608p-23"}, {"%b", float32(1.0), "8388608p-23"},
{"%b", 1.0, "4503599627370496p-52"}, {"%b", 1.0, "4503599627370496p-52"},
// Precision has no effect for binary float format.
{"%.4b", float32(1.0), "8388608p-23"},
{"%.4b", -1.0, "-4503599627370496p-52"},
// float infinites and NaNs
{"%f", posInf, "+Inf"},
{"%.1f", negInf, "-Inf"},
{"% f", NaN, " NaN"},
{"%20f", posInf, " +Inf"},
{"% 20F", posInf, " Inf"},
{"% 20e", negInf, " -Inf"},
{"%+20E", negInf, " -Inf"},
{"% +20g", negInf, " -Inf"},
{"%+-20G", posInf, "+Inf "},
{"%20e", NaN, " NaN"},
{"% +20E", NaN, " +NaN"},
{"% -20g", NaN, " NaN "},
{"%+-20G", NaN, "+NaN "},
// Zero padding does not apply to infinities and NaN.
{"%+020e", posInf, " +Inf"},
{"%-020f", negInf, "-Inf "},
{"%-020E", NaN, "NaN "},
// complex values // complex values
{"%.f", 0i, "(0+0i)"}, {"%.f", 0i, "(0+0i)"},
{"% .f", 0i, "( 0+0i)"},
{"%+.f", 0i, "(+0+0i)"}, {"%+.f", 0i, "(+0+0i)"},
{"% +.f", 0i, "(+0+0i)"}, {"% +.f", 0i, "(+0+0i)"},
{"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"}, {"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
...@@ -368,10 +396,31 @@ var fmtTests = []struct { ...@@ -368,10 +396,31 @@ var fmtTests = []struct {
{"%.3f", -1 - 2i, "(-1.000-2.000i)"}, {"%.3f", -1 - 2i, "(-1.000-2.000i)"},
{"%.3g", -1 - 2i, "(-1-2i)"}, {"%.3g", -1 - 2i, "(-1-2i)"},
{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"}, {"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
{"%+.3g", 1 + 2i, "(+1+2i)"},
{"%+.3g", complex64(1 + 2i), "(+1+2i)"}, {"%+.3g", complex64(1 + 2i), "(+1+2i)"},
{"%+.3g", complex128(1 + 2i), "(+1+2i)"},
{"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
{"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, {"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
{"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
// Precision has no effect for binary complex format.
{"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
{"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
// complex infinites and NaNs
{"%f", complex(posInf, posInf), "(+Inf+Infi)"},
{"%f", complex(negInf, negInf), "(-Inf-Infi)"},
{"%f", complex(NaN, NaN), "(NaN+NaNi)"},
{"%.1f", complex(posInf, posInf), "(+Inf+Infi)"},
{"% f", complex(posInf, posInf), "( Inf+Infi)"},
{"% f", complex(negInf, negInf), "(-Inf-Infi)"},
{"% f", complex(NaN, NaN), "( NaN+NaNi)"},
{"%8e", complex(posInf, posInf), "( +Inf +Infi)"},
{"% 8E", complex(posInf, posInf), "( Inf +Infi)"},
{"%+8f", complex(negInf, negInf), "( -Inf -Infi)"},
{"% +8g", complex(negInf, negInf), "( -Inf -Infi)"},
{"% -8G", complex(NaN, NaN), "( NaN +NaN i)"},
{"%+-8b", complex(NaN, NaN), "(+NaN +NaN i)"},
// Zero padding does not apply to infinities and NaN.
{"%08f", complex(posInf, posInf), "( +Inf +Infi)"},
{"%-08g", complex(negInf, negInf), "(-Inf -Inf i)"},
{"%-08G", complex(NaN, NaN), "(NaN +NaN i)"},
// erroneous formats // erroneous formats
{"", 2, "%!(EXTRA int=2)"}, {"", 2, "%!(EXTRA int=2)"},
...@@ -455,16 +504,6 @@ var fmtTests = []struct { ...@@ -455,16 +504,6 @@ var fmtTests = []struct {
{"%g", 1.23456789e3, "1234.56789"}, {"%g", 1.23456789e3, "1234.56789"},
{"%g", 1.23456789e-3, "0.00123456789"}, {"%g", 1.23456789e-3, "0.00123456789"},
{"%g", 1.23456789e20, "1.23456789e+20"}, {"%g", 1.23456789e20, "1.23456789e+20"},
{"%20e", math.Inf(1), " +Inf"},
{"% 20f", math.Inf(1), " Inf"},
{"%+20f", math.Inf(1), " +Inf"},
{"% +20f", math.Inf(1), " +Inf"},
{"%-20f", math.Inf(-1), "-Inf "},
{"%20g", math.NaN(), " NaN"},
{"%+20f", math.NaN(), " +NaN"},
{"% +20f", math.NaN(), " +NaN"},
{"% -20f", math.NaN(), " NaN "},
{"%+-20f", math.NaN(), "+NaN "},
// arrays // arrays
{"%v", array, "[1 2 3 4 5]"}, {"%v", array, "[1 2 3 4 5]"},
...@@ -533,10 +572,13 @@ var fmtTests = []struct { ...@@ -533,10 +572,13 @@ var fmtTests = []struct {
{"%# -6d", []byte{1, 11, 111}, "[ 1 11 111 ]"}, {"%# -6d", []byte{1, 11, 111}, "[ 1 11 111 ]"},
{"%#+-6d", [3]byte{1, 11, 111}, "[+1 +11 +111 ]"}, {"%#+-6d", [3]byte{1, 11, 111}, "[+1 +11 +111 ]"},
// floates with %v
{"%v", 1.2345678, "1.2345678"},
{"%v", float32(1.2345678), "1.2345678"},
// complexes with %v // complexes with %v
{"%v", 1 + 2i, "(1+2i)"}, {"%v", 1 + 2i, "(1+2i)"},
{"%v", complex64(1 + 2i), "(1+2i)"}, {"%v", complex64(1 + 2i), "(1+2i)"},
{"%v", complex128(1 + 2i), "(1+2i)"},
// structs // structs
{"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`}, {"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
...@@ -578,6 +620,8 @@ var fmtTests = []struct { ...@@ -578,6 +620,8 @@ var fmtTests = []struct {
{"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`}, {"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
{"%#v", []byte(nil), "[]byte(nil)"}, {"%#v", []byte(nil), "[]byte(nil)"},
{"%#v", []int32(nil), "[]int32(nil)"}, {"%#v", []int32(nil), "[]int32(nil)"},
{"%#v", 1.2345678, "1.2345678"},
{"%#v", float32(1.2345678), "1.2345678"},
// slices with other formats // slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`}, {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
...@@ -732,7 +776,7 @@ var fmtTests = []struct { ...@@ -732,7 +776,7 @@ var fmtTests = []struct {
// be fetched directly, the lookup fails and returns a // be fetched directly, the lookup fails and returns a
// zero reflect.Value, which formats as <nil>. // zero reflect.Value, which formats as <nil>.
// This test is just to check that it shows the two NaNs at all. // This test is just to check that it shows the two NaNs at all.
{"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"}, {"%v", map[float64]int{NaN: 1, NaN: 2}, "map[NaN:<nil> NaN:<nil>]"},
// Used to crash because nByte didn't allow for a sign. // Used to crash because nByte didn't allow for a sign.
{"%b", int64(-1 << 63), zeroFill("-1", 63, "")}, {"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
...@@ -822,19 +866,7 @@ var fmtTests = []struct { ...@@ -822,19 +866,7 @@ var fmtTests = []struct {
// Complex numbers: exhaustively tested in TestComplexFormatting. // Complex numbers: exhaustively tested in TestComplexFormatting.
{"%7.2f", 1 + 2i, "( 1.00 +2.00i)"}, {"%7.2f", 1 + 2i, "( 1.00 +2.00i)"},
{"%+07.2f", -1 - 2i, "(-001.00-002.00i)"}, {"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
// Zero padding does not apply to infinities and NaN.
{"%020f", math.Inf(-1), " -Inf"},
{"%020f", math.Inf(+1), " +Inf"},
{"%020f", math.NaN(), " NaN"},
{"% 020f", math.Inf(-1), " -Inf"},
{"% 020f", math.Inf(+1), " Inf"},
{"% 020f", math.NaN(), " NaN"},
{"%+020f", math.Inf(-1), " -Inf"},
{"%+020f", math.Inf(+1), " +Inf"},
{"%+020f", math.NaN(), " +NaN"},
{"%-020f", math.Inf(-1), "-Inf "},
{"%-020f", math.Inf(+1), "+Inf "},
{"%-020f", math.NaN(), "NaN "},
{"%20f", -1.0, " -1.000000"}, {"%20f", -1.0, " -1.000000"},
// Make sure we can handle very large widths. // Make sure we can handle very large widths.
{"%0100f", -1.0, zeroFill("-", 99, "1.000000")}, {"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
...@@ -925,6 +957,10 @@ var fmtTests = []struct { ...@@ -925,6 +957,10 @@ var fmtTests = []struct {
{"%☠", []uint8{0}, "%!☠([]uint8=[0])"}, {"%☠", []uint8{0}, "%!☠([]uint8=[0])"},
{"%☠", [1]byte{0}, "%!☠([1]uint8=[0])"}, {"%☠", [1]byte{0}, "%!☠([1]uint8=[0])"},
{"%☠", [1]uint8{0}, "%!☠([1]uint8=[0])"}, {"%☠", [1]uint8{0}, "%!☠([1]uint8=[0])"},
{"%☠", 1.2345678, "%!☠(float64=1.2345678)"},
{"%☠", float32(1.2345678), "%!☠(float32=1.2345678)"},
{"%☠", 1.2345678 + 1.2345678i, "%!☠(complex128=(1.2345678+1.2345678i))"},
{"%☠", complex64(1.2345678 + 1.2345678i), "%!☠(complex64=(1.2345678+1.2345678i))"},
} }
// zeroFill generates zero-filled strings of the specified width. The length // zeroFill generates zero-filled strings of the specified width. The length
...@@ -974,7 +1010,7 @@ func TestSprintf(t *testing.T) { ...@@ -974,7 +1010,7 @@ func TestSprintf(t *testing.T) {
// thing as if done by hand with two singleton prints. // thing as if done by hand with two singleton prints.
func TestComplexFormatting(t *testing.T) { func TestComplexFormatting(t *testing.T) {
var yesNo = []bool{true, false} var yesNo = []bool{true, false}
var values = []float64{1, 0, -1, math.Inf(1), math.Inf(-1), math.NaN()} var values = []float64{1, 0, -1, posInf, negInf, NaN}
for _, plus := range yesNo { for _, plus := range yesNo {
for _, zero := range yesNo { for _, zero := range yesNo {
for _, space := range yesNo { for _, space := range yesNo {
...@@ -1140,6 +1176,14 @@ func BenchmarkSprintfFloat(b *testing.B) { ...@@ -1140,6 +1176,14 @@ func BenchmarkSprintfFloat(b *testing.B) {
}) })
} }
func BenchmarkSprintfComplex(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Sprintf("%f", 5.23184+5.23184i)
}
})
}
func BenchmarkSprintfBoolean(b *testing.B) { func BenchmarkSprintfBoolean(b *testing.B) {
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
for pb.Next() { for pb.Next() {
......
...@@ -405,19 +405,15 @@ func (f *fmt) fmt_qc(c int64) { ...@@ -405,19 +405,15 @@ func (f *fmt) fmt_qc(c int64) {
} }
} }
// floating-point // fmt_float formats a float64. It assumes that verb is a valid format specifier
// for strconv.AppendFloat and therefore fits into a byte.
func doPrec(f *fmt, def int) int { func (f *fmt) fmt_float(v float64, size int, verb rune, prec int) {
// Explicit precision in format specifier overrules default precision.
if f.precPresent { if f.precPresent {
return f.prec prec = f.prec
} }
return def
}
// 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) {
// Format number, reserving space for leading + sign if needed. // Format number, reserving space for leading + sign if needed.
num := strconv.AppendFloat(f.intbuf[:1], v, verb, prec, n) num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
if num[1] == '-' || num[1] == '+' { if num[1] == '-' || num[1] == '+' {
num = num[1:] num = num[1:]
} else { } else {
...@@ -458,86 +454,3 @@ func (f *fmt) formatFloat(v float64, verb byte, prec, n int) { ...@@ -458,86 +454,3 @@ func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
// No sign to show and the number is positive; just print the unsigned number. // No sign to show and the number is positive; just print the unsigned number.
f.pad(num[1:]) f.pad(num[1:])
} }
// fmt_e64 formats a float64 in the form -1.23e+12.
func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
// fmt_E64 formats a float64 in the form -1.23E+12.
func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
// fmt_f64 formats a float64 in the form -1.23.
func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
// fmt_G64 formats a float64 in the 'f' or 'E' form according to size.
func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
// float32
// cannot defer to float64 versions
// because it will get rounding wrong in corner cases.
// fmt_e32 formats a float32 in the form -1.23e+12.
func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
// fmt_E32 formats a float32 in the form -1.23E+12.
func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
// fmt_f32 formats a float32 in the form -1.23.
func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
// fmt_c64 formats a complex64 according to the verb.
func (f *fmt) fmt_c64(v complex64, verb rune) {
f.fmt_complex(float64(real(v)), float64(imag(v)), 32, verb)
}
// fmt_c128 formats a complex128 according to the verb.
func (f *fmt) fmt_c128(v complex128, verb rune) {
f.fmt_complex(real(v), imag(v), 64, verb)
}
// fmt_complex formats a complex number as (r+ji).
func (f *fmt) fmt_complex(r, j float64, size int, verb rune) {
f.buf.WriteByte('(')
oldPlus := f.plus
oldSpace := f.space
for i := 0; ; i++ {
switch verb {
case 'b':
f.formatFloat(r, 'b', 0, size)
case 'e':
f.formatFloat(r, 'e', doPrec(f, 6), size)
case 'E':
f.formatFloat(r, 'E', doPrec(f, 6), size)
case 'f', 'F':
f.formatFloat(r, 'f', doPrec(f, 6), size)
case 'g':
f.formatFloat(r, 'g', doPrec(f, -1), size)
case 'G':
f.formatFloat(r, 'G', doPrec(f, -1), size)
}
if i != 0 {
break
}
// Imaginary part always has a sign.
f.plus = true
f.space = false
r = j
}
f.space = oldSpace
f.plus = oldPlus
f.buf.WriteString("i)")
}
...@@ -441,61 +441,39 @@ func (p *pp) fmtUint64(v uint64, verb rune) { ...@@ -441,61 +441,39 @@ func (p *pp) fmtUint64(v uint64, verb rune) {
} }
} }
func (p *pp) fmtFloat32(v float32, verb rune) { // fmtFloat formats a float. The default precision for each verb
// is specified as last argument in the call to fmt_float.
func (p *pp) fmtFloat(v float64, size int, verb rune) {
switch verb { switch verb {
case 'b':
p.fmt.fmt_fb32(v)
case 'e':
p.fmt.fmt_e32(v)
case 'E':
p.fmt.fmt_E32(v)
case 'f', 'F':
p.fmt.fmt_f32(v)
case 'g', 'v':
p.fmt.fmt_g32(v)
case 'G':
p.fmt.fmt_G32(v)
default:
p.badVerb(verb)
}
}
func (p *pp) fmtFloat64(v float64, verb rune) {
switch verb {
case 'b':
p.fmt.fmt_fb64(v)
case 'e':
p.fmt.fmt_e64(v)
case 'E':
p.fmt.fmt_E64(v)
case 'f', 'F':
p.fmt.fmt_f64(v)
case 'g', 'v':
p.fmt.fmt_g64(v)
case 'G':
p.fmt.fmt_G64(v)
default:
p.badVerb(verb)
}
}
func (p *pp) fmtComplex64(v complex64, verb rune) {
switch verb {
case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c64(v, verb)
case 'v': case 'v':
p.fmt.fmt_c64(v, 'g') p.fmt.fmt_float(v, size, 'g', -1)
case 'b', 'g', 'G':
p.fmt.fmt_float(v, size, verb, -1)
case 'f', 'e', 'E':
p.fmt.fmt_float(v, size, verb, 6)
case 'F':
p.fmt.fmt_float(v, size, 'f', 6)
default: default:
p.badVerb(verb) p.badVerb(verb)
} }
} }
func (p *pp) fmtComplex128(v complex128, verb rune) { // fmtComplex formats a complex number v with
// r = real(v) and j = imag(v) as (r+ji) using
// fmtFloat for r and j formatting.
func (p *pp) fmtComplex(v complex128, size int, verb rune) {
// Make sure any unsupported verbs are found before the
// calls to fmtFloat to not generate an incorrect error string.
switch verb { switch verb {
case 'b', 'e', 'E', 'f', 'F', 'g', 'G': case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E':
p.fmt.fmt_c128(v, verb) oldPlus := p.fmt.plus
case 'v': p.buf.WriteByte('(')
p.fmt.fmt_c128(v, 'g') p.fmtFloat(real(v), size/2, verb)
// Imaginary part always has a sign.
p.fmt.plus = true
p.fmtFloat(imag(v), size/2, verb)
p.buf.WriteString("i)")
p.fmt.plus = oldPlus
default: default:
p.badVerb(verb) p.badVerb(verb)
} }
...@@ -744,13 +722,13 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) { ...@@ -744,13 +722,13 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) {
case bool: case bool:
p.fmtBool(f, verb) p.fmtBool(f, verb)
case float32: case float32:
p.fmtFloat32(f, verb) p.fmtFloat(float64(f), 32, verb)
case float64: case float64:
p.fmtFloat64(f, verb) p.fmtFloat(f, 64, verb)
case complex64: case complex64:
p.fmtComplex64(f, verb) p.fmtComplex(complex128(f), 64, verb)
case complex128: case complex128:
p.fmtComplex128(f, verb) p.fmtComplex(f, 128, verb)
case int: case int:
p.fmtInt64(int64(f), verb) p.fmtInt64(int64(f), verb)
case int8: case int8:
...@@ -845,18 +823,14 @@ BigSwitch: ...@@ -845,18 +823,14 @@ BigSwitch:
p.fmtInt64(f.Int(), verb) p.fmtInt64(f.Int(), verb)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p.fmtUint64(f.Uint(), verb) p.fmtUint64(f.Uint(), verb)
case reflect.Float32, reflect.Float64: case reflect.Float32:
if f.Type().Size() == 4 { p.fmtFloat(f.Float(), 32, verb)
p.fmtFloat32(float32(f.Float()), verb) case reflect.Float64:
} else { p.fmtFloat(f.Float(), 64, verb)
p.fmtFloat64(f.Float(), verb) case reflect.Complex64:
} p.fmtComplex(f.Complex(), 64, verb)
case reflect.Complex64, reflect.Complex128: case reflect.Complex128:
if f.Type().Size() == 8 { p.fmtComplex(f.Complex(), 128, verb)
p.fmtComplex64(complex64(f.Complex()), verb)
} else {
p.fmtComplex128(f.Complex(), verb)
}
case reflect.String: case reflect.String:
p.fmtString(f.String(), verb) p.fmtString(f.String(), verb)
case reflect.Map: case reflect.Map:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment