mirror of
https://github.com/golang/go
synced 2024-11-12 10:20:27 -07:00
fmt: add verbs:
%E - upper case %e %G - upper case %g %#v - Go syntax R=r DELTA=332 (238 added, 47 deleted, 47 changed) OCL=34091 CL=34145
This commit is contained in:
parent
e596297139
commit
a843b4541a
@ -10,6 +10,7 @@ import (
|
||||
"math";
|
||||
"strings";
|
||||
"testing";
|
||||
"unsafe";
|
||||
)
|
||||
|
||||
func TestFmtInterface(t *testing.T) {
|
||||
@ -32,6 +33,15 @@ const b64 uint64 = 1<<64 - 1
|
||||
var array = []int{1, 2, 3, 4, 5}
|
||||
var iarray = []interface{}{1, "hello", 2.5, nil}
|
||||
|
||||
type A struct {
|
||||
i int;
|
||||
j uint;
|
||||
s string;
|
||||
x []int;
|
||||
}
|
||||
|
||||
var b byte;
|
||||
|
||||
var fmttests = []fmtTest{
|
||||
// basic string
|
||||
fmtTest{ "%s", "abc", "abc" },
|
||||
@ -79,15 +89,9 @@ var fmttests = []fmtTest{
|
||||
fmtTest{ "%+d", -12345, "-12345" },
|
||||
fmtTest{ "% d", 12345, " 12345" },
|
||||
|
||||
// arrays
|
||||
fmtTest{ "%v", array, "[1 2 3 4 5]" },
|
||||
fmtTest{ "%v", iarray, "[1 hello 2.5 <nil>]" },
|
||||
fmtTest{ "%v", &array, "&[1 2 3 4 5]" },
|
||||
fmtTest{ "%v", &iarray, "&[1 hello 2.5 <nil>]" },
|
||||
|
||||
// erroneous formats
|
||||
fmtTest{ "", 2, "?(extra int=2)" },
|
||||
fmtTest{ "%d", "hello", "%d(string=hello)%" },
|
||||
fmtTest{ "%d", "hello", "%d(string=hello)" },
|
||||
|
||||
// old test/fmt_test.go
|
||||
fmtTest{ "%d", 1234, "1234" },
|
||||
@ -123,6 +127,17 @@ var fmttests = []fmtTest{
|
||||
fmtTest{ "%g", float64(-7), "-7" },
|
||||
fmtTest{ "%g", float64(-1e-9), "-1e-09", },
|
||||
fmtTest{ "%g", float32(-1e-9), "-1e-09" },
|
||||
fmtTest{ "%E", float64(1), "1.000000E+00" },
|
||||
fmtTest{ "%E", float64(1234.5678e3), "1.234568E+06" },
|
||||
fmtTest{ "%E", float64(1234.5678e-8), "1.234568E-05" },
|
||||
fmtTest{ "%E", float64(-7), "-7.000000E+00" },
|
||||
fmtTest{ "%E", float64(-1e-9), "-1.000000E-09" },
|
||||
fmtTest{ "%G", float64(1234.5678e3), "1.2345678E+06" },
|
||||
fmtTest{ "%G", float32(1234.5678e3), "1.2345678E+06" },
|
||||
fmtTest{ "%G", float64(1234.5678e-8), "1.2345678E-05" },
|
||||
fmtTest{ "%G", float64(-7), "-7" },
|
||||
fmtTest{ "%G", float64(-1e-9), "-1E-09", },
|
||||
fmtTest{ "%G", float32(-1e-9), "-1E-09" },
|
||||
fmtTest{ "%c", 'x', "x" },
|
||||
fmtTest{ "%c", 0xe4, "ä" },
|
||||
fmtTest{ "%c", 0x672c, "本" },
|
||||
@ -158,11 +173,39 @@ var fmttests = []fmtTest{
|
||||
fmtTest{ "%20e", math.Inf(1), " +Inf" },
|
||||
fmtTest{ "%-20f", math.Inf(-1), "-Inf " },
|
||||
fmtTest{ "%20g", math.NaN(), " NaN" },
|
||||
|
||||
// arrays
|
||||
fmtTest{ "%v", array, "[1 2 3 4 5]" },
|
||||
fmtTest{ "%v", iarray, "[1 hello 2.5 <nil>]" },
|
||||
fmtTest{ "%v", &array, "&[1 2 3 4 5]" },
|
||||
fmtTest{ "%v", &iarray, "&[1 hello 2.5 <nil>]" },
|
||||
|
||||
// structs
|
||||
fmtTest{ "%v", A{1,2,"a",[]int{1,2}}, `{1 2 a [1 2]}` },
|
||||
fmtTest{ "%+v", A{1,2,"a",[]int{1,2}}, `{i:1 j:2 s:a x:[1 2]}` },
|
||||
|
||||
// go syntax
|
||||
fmtTest{ "%#v", A{1,2,"a",[]int{1,2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}` },
|
||||
fmtTest{ "%#v", &b, "(*uint8)(PTR)" },
|
||||
fmtTest{ "%#v", TestFmtInterface, "(func(*testing.T))(PTR)" },
|
||||
fmtTest{ "%#v", make(chan int), "(chan int)(PTR)" },
|
||||
fmtTest{ "%#v", uint64(1<<64-1), "0xffffffffffffffff" },
|
||||
fmtTest{ "%#v", 1000000000, "1000000000" },
|
||||
}
|
||||
|
||||
func TestSprintf(t *testing.T) {
|
||||
for i, tt := range fmttests {
|
||||
s := Sprintf(tt.fmt, tt.val);
|
||||
if i := strings.Index(s, "0x"); i >= 0 && strings.Index(tt.out, "PTR") >= 0 {
|
||||
j := i+2;
|
||||
for ; j < len(s); j++ {
|
||||
c := s[j];
|
||||
if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
s = s[0:i] + "PTR" + s[j:len(s)];
|
||||
}
|
||||
if s != tt.out {
|
||||
if ss, ok := tt.val.(string); ok {
|
||||
// Don't requote the already-quoted strings.
|
||||
|
@ -465,6 +465,11 @@ func (f *Fmt) Fmt_e64(v float64) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa64(v, 'e', doPrec(f, 6)));
|
||||
}
|
||||
|
||||
// Fmt_E64 formats a float64 in the form -1.23E+12.
|
||||
func (f *Fmt) Fmt_E64(v float64) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa64(v, 'E', doPrec(f, 6)));
|
||||
}
|
||||
|
||||
// Fmt_f64 formats a float64 in the form -1.23.
|
||||
func (f *Fmt) Fmt_f64(v float64) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa64(v, 'f', doPrec(f, 6)));
|
||||
@ -475,6 +480,11 @@ func (f *Fmt) Fmt_g64(v float64) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa64(v, 'g', doPrec(f, -1)));
|
||||
}
|
||||
|
||||
// Fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
|
||||
func (f *Fmt) Fmt_G64(v float64) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa64(v, 'G', doPrec(f, -1)));
|
||||
}
|
||||
|
||||
// Fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
|
||||
func (f *Fmt) Fmt_fb64(v float64) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa64(v, 'b', 0));
|
||||
@ -489,6 +499,11 @@ func (f *Fmt) Fmt_e32(v float32) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa32(v, 'e', doPrec(f, 6)));
|
||||
}
|
||||
|
||||
// Fmt_E32 formats a float32 in the form -1.23E+12.
|
||||
func (f *Fmt) Fmt_E32(v float32) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa32(v, 'e', doPrec(f, 6)));
|
||||
}
|
||||
|
||||
// Fmt_f32 formats a float32 in the form -1.23.
|
||||
func (f *Fmt) Fmt_f32(v float32) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa32(v, 'f', doPrec(f, 6)));
|
||||
@ -499,6 +514,11 @@ func (f *Fmt) Fmt_g32(v float32) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa32(v, 'g', doPrec(f, -1)));
|
||||
}
|
||||
|
||||
// Fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
|
||||
func (f *Fmt) Fmt_G32(v float32) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa32(v, 'G', doPrec(f, -1)));
|
||||
}
|
||||
|
||||
// Fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
|
||||
func (f *Fmt) Fmt_fb32(v float32) *Fmt {
|
||||
return fmtString(f, strconv.Ftoa32(v, 'b', 0));
|
||||
|
@ -10,8 +10,11 @@
|
||||
The verbs:
|
||||
|
||||
General:
|
||||
%v for any operand type, the value in a default format.
|
||||
%v the value in a default format.
|
||||
when printing structs, the plus flag (%+v) adds field names
|
||||
%#v a Go-syntax representation of the value
|
||||
%T a Go-syntax representation of the type of the value
|
||||
|
||||
Boolean:
|
||||
%t the word true or false
|
||||
Integer:
|
||||
@ -23,16 +26,16 @@
|
||||
%X base 16, with upper-case letters for A-F
|
||||
Floating-point:
|
||||
%e scientific notation, e.g. -1234.456e+78
|
||||
%E scientific notation, e.g. -1234.456E+78
|
||||
%f decimal point but no exponent, e.g. 123.456
|
||||
%g whichever of %e or %f produces more compact output
|
||||
%G whichever of %E or %f produces more compact output
|
||||
String and slice of bytes:
|
||||
%s the uninterpreted bytes of the string or slice
|
||||
%q a double-quoted string safely escaped with Go syntax
|
||||
%x base 16 notation with two characters per byte
|
||||
Pointer:
|
||||
%p base 16 notation, with leading 0x
|
||||
Type:
|
||||
%T a Go-syntax representation of the type of the operand
|
||||
|
||||
There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
|
||||
Similarly, there is no need to specify the size of the operand (int8, int64).
|
||||
@ -95,21 +98,29 @@ type State interface {
|
||||
Flag(int) bool;
|
||||
}
|
||||
|
||||
// Formatter is the interface implemented by objects with a custom formatter.
|
||||
// Formatter is the interface implemented by values with a custom formatter.
|
||||
// The implementation of Format may call Sprintf or Fprintf(f) etc.
|
||||
// to generate its output.
|
||||
type Formatter interface {
|
||||
Format(f State, c int);
|
||||
}
|
||||
|
||||
// String represents any object being printed that has a String() method that
|
||||
// returns a string, which defines the ``native'' format for that object.
|
||||
// Any such object will be printed using that method if passed
|
||||
// as operand to a %s or %v format or to an unformatted printer such as Print.
|
||||
// Stringer is implemented by any value that has a String method(),
|
||||
// which defines the ``native'' format for that value.
|
||||
// The String method is used to print values passed as an operand
|
||||
// to a %s or %v format or to an unformatted printer such as Print.
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// GoStringer is implemented by any value that has a GoString() method,
|
||||
// which defines the Go syntax for that value.
|
||||
// The GoString method is used to print values passed as an operand
|
||||
// to a %#v format.
|
||||
type GoStringer interface {
|
||||
GoString() string
|
||||
}
|
||||
|
||||
const runeSelf = utf8.RuneSelf
|
||||
const allocSize = 32
|
||||
|
||||
@ -392,15 +403,28 @@ func parsenum(s string, start, end int) (n int, got bool, newi int) {
|
||||
return num, isnum, start;
|
||||
}
|
||||
|
||||
func (p *pp) printField(field reflect.Value) (was_string bool) {
|
||||
type uintptrGetter interface {
|
||||
Get() uintptr;
|
||||
}
|
||||
|
||||
func (p *pp) printField(field reflect.Value, plus, sharp bool, depth int) (was_string bool) {
|
||||
inter := field.Interface();
|
||||
if inter != nil {
|
||||
if stringer, ok := inter.(Stringer); ok {
|
||||
p.addstr(stringer.String());
|
||||
return false; // this value is not a string
|
||||
switch {
|
||||
default:
|
||||
if stringer, ok := inter.(Stringer); ok {
|
||||
p.addstr(stringer.String());
|
||||
return false; // this value is not a string
|
||||
}
|
||||
case sharp:
|
||||
if stringer, ok := inter.(GoStringer); ok {
|
||||
p.addstr(stringer.GoString());
|
||||
return false; // this value is not a string
|
||||
}
|
||||
}
|
||||
}
|
||||
s := "";
|
||||
BigSwitch:
|
||||
switch f := field.(type) {
|
||||
case *reflect.BoolValue:
|
||||
s = p.fmt.Fmt_boolean(f.Get()).Str();
|
||||
@ -415,79 +439,160 @@ func (p *pp) printField(field reflect.Value) (was_string bool) {
|
||||
s = p.fmt.Fmt_g64(float64(f.Get())).Str();
|
||||
}
|
||||
case *reflect.StringValue:
|
||||
s = p.fmt.Fmt_s(f.Get()).Str();
|
||||
was_string = true;
|
||||
case *reflect.PtrValue:
|
||||
v := f.Get();
|
||||
if v == 0 {
|
||||
s = "<nil>";
|
||||
break;
|
||||
if sharp {
|
||||
s = p.fmt.Fmt_q(f.Get()).Str();
|
||||
} else {
|
||||
s = p.fmt.Fmt_s(f.Get()).Str();
|
||||
was_string = true;
|
||||
}
|
||||
// pointer to array?
|
||||
if a, ok := f.Elem().(reflect.ArrayOrSliceValue); ok {
|
||||
p.addstr("&");
|
||||
p.printField(a);
|
||||
break;
|
||||
}
|
||||
p.fmt.sharp = !p.fmt.sharp; // turn 0x on by default
|
||||
s = p.fmt.Fmt_ux64(uint64(v)).Str();
|
||||
case reflect.ArrayOrSliceValue:
|
||||
p.addstr("[");
|
||||
for i := 0; i < f.Len(); i++ {
|
||||
if i > 0 {
|
||||
p.addstr(" ");
|
||||
}
|
||||
p.printField(f.Elem(i));
|
||||
}
|
||||
p.addstr("]");
|
||||
case *reflect.MapValue:
|
||||
p.addstr("map[");
|
||||
if sharp {
|
||||
p.addstr(field.Type().String());
|
||||
p.addstr("{");
|
||||
} else {
|
||||
p.addstr("map[");
|
||||
}
|
||||
keys := f.Keys();
|
||||
for i, key := range keys {
|
||||
if i > 0 {
|
||||
p.addstr(" ");
|
||||
if sharp {
|
||||
p.addstr(", ");
|
||||
} else {
|
||||
p.addstr(" ");
|
||||
}
|
||||
}
|
||||
p.printField(key);
|
||||
p.printField(key, plus, sharp, depth+1);
|
||||
p.addstr(":");
|
||||
p.printField(f.Elem(key));
|
||||
p.printField(f.Elem(key), plus, sharp, depth+1);
|
||||
}
|
||||
if sharp {
|
||||
p.addstr("}");
|
||||
} else {
|
||||
p.addstr("]");
|
||||
}
|
||||
p.addstr("]");
|
||||
case *reflect.StructValue:
|
||||
if sharp {
|
||||
p.addstr(field.Type().String());
|
||||
}
|
||||
p.add('{');
|
||||
v := f;
|
||||
t := v.Type().(*reflect.StructType);
|
||||
donames := p.fmt.plus;
|
||||
p.fmt.clearflags(); // clear flags for p.printField
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if i > 0 {
|
||||
p.add(' ')
|
||||
if sharp {
|
||||
p.addstr(", ");
|
||||
} else {
|
||||
p.addstr(" ");
|
||||
}
|
||||
}
|
||||
if donames {
|
||||
if plus || sharp {
|
||||
if f := t.Field(i); f.Name != "" {
|
||||
p.addstr(f.Name);
|
||||
p.add(':');
|
||||
}
|
||||
}
|
||||
p.printField(getField(v, i));
|
||||
p.printField(getField(v, i), plus, sharp, depth+1);
|
||||
}
|
||||
p.add('}');
|
||||
p.addstr("}");
|
||||
case *reflect.InterfaceValue:
|
||||
value := f.Elem();
|
||||
if value == nil {
|
||||
s = "<nil>"
|
||||
if sharp {
|
||||
p.addstr(field.Type().String());
|
||||
p.addstr("(nil)");
|
||||
} else {
|
||||
s = "<nil>"
|
||||
}
|
||||
} else {
|
||||
return p.printField(value);
|
||||
return p.printField(value, plus, sharp, depth+1);
|
||||
}
|
||||
case reflect.ArrayOrSliceValue:
|
||||
if sharp {
|
||||
p.addstr(field.Type().String());
|
||||
p.addstr("{");
|
||||
} else {
|
||||
p.addstr("[");
|
||||
}
|
||||
for i := 0; i < f.Len(); i++ {
|
||||
if i > 0 {
|
||||
if sharp {
|
||||
p.addstr(", ");
|
||||
} else {
|
||||
p.addstr(" ");
|
||||
}
|
||||
}
|
||||
p.printField(f.Elem(i), plus, sharp, depth+1);
|
||||
}
|
||||
if sharp {
|
||||
p.addstr("}");
|
||||
} else {
|
||||
p.addstr("]");
|
||||
}
|
||||
case *reflect.PtrValue:
|
||||
v := f.Get();
|
||||
// pointer to array or slice or struct? ok at top level
|
||||
// but not embedded (avoid loops)
|
||||
if v != 0 && depth == 0 {
|
||||
switch a := f.Elem().(type) {
|
||||
case reflect.ArrayOrSliceValue:
|
||||
p.addstr("&");
|
||||
p.printField(a, plus, sharp, depth+1);
|
||||
break BigSwitch;
|
||||
case *reflect.StructValue:
|
||||
p.addstr("&");
|
||||
p.printField(a, plus, sharp, depth+1);
|
||||
break BigSwitch;
|
||||
}
|
||||
}
|
||||
if sharp {
|
||||
p.addstr("(");
|
||||
p.addstr(field.Type().String());
|
||||
p.addstr(")(");
|
||||
if v == 0 {
|
||||
p.addstr("nil");
|
||||
} else {
|
||||
p.fmt.sharp = true;
|
||||
p.addstr(p.fmt.Fmt_ux64(uint64(v)).Str());
|
||||
}
|
||||
p.addstr(")");
|
||||
break;
|
||||
}
|
||||
if v == 0 {
|
||||
s = "<nil>";
|
||||
break;
|
||||
}
|
||||
p.fmt.sharp = true; // turn 0x on
|
||||
s = p.fmt.Fmt_ux64(uint64(v)).Str();
|
||||
case uintptrGetter:
|
||||
v := f.Get();
|
||||
if sharp {
|
||||
p.addstr("(");
|
||||
p.addstr(field.Type().String());
|
||||
p.addstr(")(");
|
||||
if v == 0 {
|
||||
p.addstr("nil");
|
||||
} else {
|
||||
p.fmt.sharp = true;
|
||||
p.addstr(p.fmt.Fmt_ux64(uint64(v)).Str());
|
||||
}
|
||||
p.addstr(")");
|
||||
} else {
|
||||
p.fmt.sharp = true; // turn 0x on
|
||||
p.addstr(p.fmt.Fmt_ux64(uint64(f.Get())).Str());
|
||||
}
|
||||
case *reflect.UintptrValue:
|
||||
p.fmt.sharp = !p.fmt.sharp; // turn 0x on by default
|
||||
s = p.fmt.Fmt_ux64(uint64(f.Get())).Str();
|
||||
default:
|
||||
v, signed, ok := getInt(field);
|
||||
if ok {
|
||||
if signed {
|
||||
s = p.fmt.Fmt_d64(v).Str();
|
||||
} else {
|
||||
s = p.fmt.Fmt_ud64(uint64(v)).Str();
|
||||
if sharp {
|
||||
p.fmt.sharp = true; // turn on 0x
|
||||
s = p.fmt.Fmt_ux64(uint64(v)).Str();
|
||||
} else {
|
||||
s = p.fmt.Fmt_ud64(uint64(v)).Str();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -548,13 +653,17 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
|
||||
}
|
||||
field := getField(v, fieldnum);
|
||||
fieldnum++;
|
||||
|
||||
// Try formatter except for %T,
|
||||
// which is special and handled internally.
|
||||
inter := field.Interface();
|
||||
if inter != nil && c != 'T' { // don't want thing to describe itself if we're asking for its type
|
||||
if inter != nil && c != 'T' {
|
||||
if formatter, ok := inter.(Formatter); ok {
|
||||
formatter.Format(p, c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
s := "";
|
||||
switch c {
|
||||
// bool
|
||||
@ -640,6 +749,14 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
|
||||
} else {
|
||||
goto badtype
|
||||
}
|
||||
case 'E':
|
||||
if v, ok := getFloat32(field); ok {
|
||||
s = p.fmt.Fmt_E32(v).Str()
|
||||
} else if v, ok := getFloat64(field); ok {
|
||||
s = p.fmt.Fmt_E64(v).Str()
|
||||
} else {
|
||||
goto badtype
|
||||
}
|
||||
case 'f':
|
||||
if v, ok := getFloat32(field); ok {
|
||||
s = p.fmt.Fmt_f32(v).Str()
|
||||
@ -656,6 +773,14 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
|
||||
} else {
|
||||
goto badtype
|
||||
}
|
||||
case 'G':
|
||||
if v, ok := getFloat32(field); ok {
|
||||
s = p.fmt.Fmt_G32(v).Str()
|
||||
} else if v, ok := getFloat64(field); ok {
|
||||
s = p.fmt.Fmt_G64(v).Str()
|
||||
} else {
|
||||
goto badtype
|
||||
}
|
||||
|
||||
// string
|
||||
case 's':
|
||||
@ -692,7 +817,10 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
|
||||
|
||||
// arbitrary value; do your best
|
||||
case 'v':
|
||||
p.printField(field);
|
||||
plus, sharp := p.fmt.plus, p.fmt.sharp;
|
||||
p.fmt.plus = false;
|
||||
p.fmt.sharp = false;
|
||||
p.printField(field, plus, sharp, 0);
|
||||
|
||||
// the value's type
|
||||
case 'T':
|
||||
@ -702,8 +830,8 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
|
||||
badtype:
|
||||
s = "%" + string(c) + "(" + field.Type().String() + "=";
|
||||
p.addstr(s);
|
||||
p.printField(field);
|
||||
s= ")%";
|
||||
p.printField(field, false, false, 0);
|
||||
s = ")";
|
||||
}
|
||||
p.addstr(s);
|
||||
}
|
||||
@ -713,7 +841,7 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
|
||||
field := getField(v, fieldnum);
|
||||
p.addstr(field.Type().String());
|
||||
p.addstr("=");
|
||||
p.printField(field);
|
||||
p.printField(field, false, false, 0);
|
||||
if fieldnum + 1 < v.NumField() {
|
||||
p.addstr(", ");
|
||||
}
|
||||
@ -733,7 +861,7 @@ func (p *pp) doprint(v *reflect.StructValue, addspace, addnewline bool) {
|
||||
p.add(' ');
|
||||
}
|
||||
}
|
||||
prev_string = p.printField(field);
|
||||
prev_string = p.printField(field, false, false, 0);
|
||||
}
|
||||
if addnewline {
|
||||
p.add('\n')
|
||||
|
@ -115,20 +115,20 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
|
||||
shortest = true;
|
||||
roundShortest(d, mant, exp, flt);
|
||||
switch fmt {
|
||||
case 'e':
|
||||
case 'e', 'E':
|
||||
prec = d.nd - 1;
|
||||
case 'f':
|
||||
prec = max(d.nd - d.dp, 0);
|
||||
case 'g':
|
||||
case 'g', 'G':
|
||||
prec = d.nd;
|
||||
}
|
||||
} else {
|
||||
switch fmt {
|
||||
case 'e':
|
||||
case 'e', 'E':
|
||||
d.Round(prec+1);
|
||||
case 'f':
|
||||
d.Round(d.dp+prec);
|
||||
case 'g':
|
||||
case 'g', 'G':
|
||||
if prec == 0 {
|
||||
prec = 1;
|
||||
}
|
||||
@ -137,11 +137,11 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
|
||||
}
|
||||
|
||||
switch fmt {
|
||||
case 'e':
|
||||
return fmtE(neg, d, prec);
|
||||
case 'e', 'E':
|
||||
return fmtE(neg, d, prec, fmt);
|
||||
case 'f':
|
||||
return fmtF(neg, d, prec);
|
||||
case 'g':
|
||||
case 'g', 'G':
|
||||
// trailing zeros are removed.
|
||||
if prec > d.nd {
|
||||
prec = d.nd;
|
||||
@ -155,7 +155,7 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
|
||||
}
|
||||
exp := d.dp - 1;
|
||||
if exp < -4 || exp >= eprec {
|
||||
return fmtE(neg, d, prec - 1);
|
||||
return fmtE(neg, d, prec - 1, fmt + 'e' - 'g');
|
||||
}
|
||||
return fmtF(neg, d, max(prec - d.dp, 0));
|
||||
}
|
||||
@ -251,7 +251,7 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
|
||||
}
|
||||
|
||||
// %e: -d.ddddde±dd
|
||||
func fmtE(neg bool, d *decimal, prec int) string {
|
||||
func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
|
||||
buf := make([]byte, 3+max(prec, 0)+30); // "-0." + prec digits + exp
|
||||
w := 0; // write index
|
||||
|
||||
@ -284,7 +284,7 @@ func fmtE(neg bool, d *decimal, prec int) string {
|
||||
}
|
||||
|
||||
// e±
|
||||
buf[w] = 'e';
|
||||
buf[w] = fmt;
|
||||
w++;
|
||||
exp := d.dp - 1;
|
||||
if d.nd == 0 { // special case: 0 has exponent 0
|
||||
|
Loading…
Reference in New Issue
Block a user