Commit e97f407e authored by Martin Möhrmann's avatar Martin Möhrmann

fmt: support sharp flag for float and complex value printing

Added an alternate form of printing floats and complex values
by specifying the sharp flag.

Output formatted using the the verbs v, e, E, f, F, g and G in
combination with the sharp flag will always include a decimal point.

The alternate form specified by the sharp flag for %g and %G verbs
will not truncate trailing zeros and assume a default precision of 6.

Fixes #18857.

Change-Id: I4d776239e06d7a6a90f2d8556240a359888cb7c3
Reviewed-on: https://go-review.googlesource.com/37051Reviewed-by: default avatarRob Pike <r@golang.org>
parent 1e69aefb
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
precision sets the number of places after the decimal, if appropriate, precision sets the number of places after the decimal, if appropriate,
except that for %g/%G precision sets the total number of significant except that for %g/%G precision sets the total number of significant
digits. For example, given 12.345 the format %6.3f prints 12.345 while digits. For example, given 12.345 the format %6.3f prints 12.345 while
%.3g prints 12.3. The default precision for %e and %f is 6; for %g it %.3g prints 12.3. The default precision for %e, %f and %#g is 6; for %g it
is the smallest number of digits necessary to identify the value uniquely. is the smallest number of digits necessary to identify the value uniquely.
For complex numbers, the width and precision apply to the two For complex numbers, the width and precision apply to the two
...@@ -109,6 +109,8 @@ ...@@ -109,6 +109,8 @@
0X for hex (%#X); suppress 0x for %p (%#p); 0X for hex (%#X); suppress 0x for %p (%#p);
for %q, print a raw (backquoted) string if strconv.CanBackquote for %q, print a raw (backquoted) string if strconv.CanBackquote
returns true; returns true;
always print a decimal point for %e, %E, %f, %F, %g and %G;
do not remove trailing zeros for %g and %G;
write e.g. U+0078 'x' if the character is printable for %U (%#U). write e.g. U+0078 'x' if the character is printable for %U (%#U).
' ' (space) leave a space for elided sign in numbers (% d); ' ' (space) leave a space for elided sign in numbers (% d);
put spaces between bytes printing strings or slices in hex (% x, % X) put spaces between bytes printing strings or slices in hex (% x, % X)
......
...@@ -416,6 +416,32 @@ var fmtTests = []struct { ...@@ -416,6 +416,32 @@ 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"},
// Test sharp flag used with floats.
{"%#g", 1e-323, "1.00000e-323"},
{"%#g", -1.0, "-1.00000"},
{"%#g", 1.1, "1.10000"},
{"%#g", 123456.0, "123456."},
{"%#g", 1234567.0, "1.234567e+06"},
{"%#g", 1230000.0, "1.23000e+06"},
{"%#g", 1000000.0, "1.00000e+06"},
{"%#.0f", 1.0, "1."},
{"%#.0e", 1.0, "1.e+00"},
{"%#.0g", 1.0, "1."},
{"%#.0g", 1100000.0, "1.e+06"},
{"%#.4f", 1.0, "1.0000"},
{"%#.4e", 1.0, "1.0000e+00"},
{"%#.4g", 1.0, "1.000"},
{"%#.4g", 100000.0, "1.000e+05"},
{"%#.0f", 123.0, "123."},
{"%#.0e", 123.0, "1.e+02"},
{"%#.0g", 123.0, "1.e+02"},
{"%#.4f", 123.0, "123.0000"},
{"%#.4e", 123.0, "1.2300e+02"},
{"%#.4g", 123.0, "123.0"},
{"%#.4g", 123000.0, "1.230e+05"},
{"%#9.4g", 1.0, " 1.000"},
// The sharp flag has no effect for binary float format.
{"%#b", 1.0, "4503599627370496p-52"},
// Precision has no effect for binary float format. // Precision has no effect for binary float format.
{"%.4b", float32(1.0), "8388608p-23"}, {"%.4b", float32(1.0), "8388608p-23"},
{"%.4b", -1.0, "-4503599627370496p-52"}, {"%.4b", -1.0, "-4503599627370496p-52"},
...@@ -466,8 +492,24 @@ var fmtTests = []struct { ...@@ -466,8 +492,24 @@ var fmtTests = []struct {
{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"}, {"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
{"%+.3g", 1 + 2i, "(+1+2i)"}, {"%+.3g", 1 + 2i, "(+1+2i)"},
{"%+.3g", complex64(1 + 2i), "(+1+2i)"}, {"%+.3g", complex64(1 + 2i), "(+1+2i)"},
{"%#g", 1 + 2i, "(1.00000+2.00000i)"},
{"%#g", 123456 + 789012i, "(123456.+789012.i)"},
{"%#g", 1e-10i, "(0.00000+1.00000e-10i)"},
{"%#g", -1e10 - 1.11e100i, "(-1.00000e+10-1.11000e+100i)"},
{"%#.0f", 1.23 + 1.0i, "(1.+1.i)"},
{"%#.0e", 1.23 + 1.0i, "(1.e+00+1.e+00i)"},
{"%#.0g", 1.23 + 1.0i, "(1.+1.i)"},
{"%#.0g", 0 + 100000i, "(0.+1.e+05i)"},
{"%#.0g", 1230000 + 0i, "(1.e+06+0.i)"},
{"%#.4f", 1 + 1.23i, "(1.0000+1.2300i)"},
{"%#.4e", 123 + 1i, "(1.2300e+02+1.0000e+00i)"},
{"%#.4g", 123 + 1.23i, "(123.0+1.230i)"},
{"%#12.5g", 0 + 100000i, "( 0.0000 +1.0000e+05i)"},
{"%#12.5g", 1230000 - 0i, "( 1.2300e+06 +0.0000i)"},
{"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, {"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
{"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"}, {"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
// The sharp flag has no effect for binary complex format.
{"%#b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
// Precision has no effect for binary complex format. // Precision has no effect for binary complex format.
{"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, {"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
{"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"}, {"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
......
...@@ -480,6 +480,46 @@ func (f *fmt) fmt_float(v float64, size int, verb rune, prec int) { ...@@ -480,6 +480,46 @@ func (f *fmt) fmt_float(v float64, size int, verb rune, prec int) {
f.zero = oldZero f.zero = oldZero
return return
} }
// The sharp flag forces printing a decimal point for non-binary formats
// and retains trailing zeros, which we may need to restore.
if f.sharp && verb != 'b' {
digits := 0
switch verb {
case 'v', 'g', 'G':
digits = prec
// If no precision is set explicitly use a precision of 6.
if digits == -1 {
digits = 6
}
}
// Buffer pre-allocated with enough room for
// exponent notations of the form "e+123".
var tailBuf [5]byte
tail := tailBuf[:0]
hasDecimalPoint := false
// Starting from i = 1 to skip sign at num[0].
for i := 1; i < len(num); i++ {
switch num[i] {
case '.':
hasDecimalPoint = true
case 'e', 'E':
tail = append(tail, num[i:]...)
num = num[:i]
default:
digits--
}
}
if !hasDecimalPoint {
num = append(num, '.')
}
for digits > 0 {
num = append(num, '0')
digits--
}
num = append(num, tail...)
}
// We want a sign if asked for and if the sign is not positive. // We want a sign if asked for and if the sign is not positive.
if f.plus || num[0] != '+' { if f.plus || num[0] != '+' {
// If we're zero padding to the left we want the sign before the leading zeros. // If we're zero padding to the left we want the sign before the leading zeros.
......
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