diff options
Diffstat (limited to 'src/lib/fmt')
| -rw-r--r-- | src/lib/fmt/Makefile | 10 | ||||
| -rw-r--r-- | src/lib/fmt/format.go | 245 | ||||
| -rw-r--r-- | src/lib/fmt/print.go | 51 |
3 files changed, 100 insertions, 206 deletions
diff --git a/src/lib/fmt/Makefile b/src/lib/fmt/Makefile index 64ca60c91f..b9148ccf04 100644 --- a/src/lib/fmt/Makefile +++ b/src/lib/fmt/Makefile @@ -10,15 +10,17 @@ CC=$(O)c -w AS=$(O)a AR=$(O)ar -PKG=$(GOROOT)/pkg/fmt.a +PKG=fmt.a +PKGDIR=$(GOROOT)/pkg install: $(PKG) + mv $(PKG) $(PKGDIR)/$(PKG) nuke: clean - rm -f $(PKG) + rm -f $(PKGDIR)/$(PKG) clean: - rm -f *.$O *.a + rm -f *.$O *.a $(PKG) %.$O: %.go $(GC) $*.go @@ -39,8 +41,10 @@ O2=\ $(PKG): a1 a2 a1: $(O1) $(AR) grc $(PKG) $(O1) + rm -f $(O1) a2: $(O2) $(AR) grc $(PKG) $(O2) + rm -f $(O2) $(O1): nuke $(O2): a1 diff --git a/src/lib/fmt/format.go b/src/lib/fmt/format.go index 089de43f40..058c619443 100644 --- a/src/lib/fmt/format.go +++ b/src/lib/fmt/format.go @@ -4,6 +4,8 @@ package fmt +import "strconv" + /* Raw formatter. See print.go for a more palatable interface. @@ -181,7 +183,7 @@ func (f *Fmt) d64(a int64) *Fmt { f.clearflags(); return f; } - + func (f *Fmt) d32(a int32) *Fmt { return f.d64(int64(a)); } @@ -332,227 +334,82 @@ func (f *Fmt) s(s string) *Fmt { return f; } -func pow10(n int) float64 { - var d float64; - - neg := false; - if n < 0 { - if n < -307 { // DBL_MIN_10_EXP - return 0.; - } - neg = true; - n = -n; - }else if n > 308 { // DBL_MAX_10_EXP - return 1.79769e+308; // HUGE_VAL - } +// floating-point - if n < NPows10 { - d = pows10[n]; - } else { - d = pows10[NPows10-1]; - for { - n -= NPows10 - 1; - if n < NPows10 { - d *= pows10[n]; - break; - } - d *= pows10[NPows10 - 1]; - } - } - if neg { - return 1/d; - } - return d; -} - -func unpack(a float64) (negative bool, exp int, num float64) { - if a == 0 { - return false, 0, 0.0 - } - neg := a < 0; - if neg { - a = -a; - } - // find g,e such that a = g*10^e. - // guess 10-exponent using 2-exponent, then fine tune. - g, e2 := sys.frexp(a); - e := int(float64(e2) * .301029995663981); - g = a * pow10(-e); - for g < 1 { - e--; - g = a * pow10(-e); - } - for g >= 10 { - e++; - g = a * pow10(-e); - } - return neg, e, g; -} - -// check for Inf, NaN -func(f *Fmt) InfOrNan(a float64) bool { - if sys.isInf(a, 0) { - if sys.isInf(a, 1) { - f.pad("Inf"); - } else { - f.pad("-Inf"); - } - f.clearflags(); - return true; - } - if sys.isNaN(a) { - f.pad("NaN"); - f.clearflags(); - return true; +func Prec(f *Fmt, def int) int { + if f.prec_present { + return f.prec; } - return false; + return def; } -// float64 -func (f *Fmt) e64(a float64) *Fmt { - var negative bool; - var g float64; - var exp int; - if f.InfOrNan(a) { - return f; - } - negative, exp, g = unpack(a); - prec := 6; - if f.prec_present { - prec = f.prec; - } - prec++; // one digit left of decimal - var s string; - // multiply by 10^prec to get decimal places; put decimal after first digit - if g == 0 { - // doesn't work for zero - fake it - s = "000000000000000000000000000000000000000000000000000000000000"; - if prec < len(s) { - s = s[0:prec]; - } else { - prec = len(s); - } - } else { - g *= pow10(prec); - s = f.integer(int64(g + .5), 10, true, &ldigits); // get the digits into a string - } - s = s[0:1] + "." + s[1:prec]; // insert a decimal point - // print exponent with leading 0 if appropriate. - es := New().p(2).integer(int64(exp), 10, true, &ldigits); - if exp >= 0 { - es = "+" + es; // TODO: should do this with a fmt flag - } - s = s + "e" + es; - if negative { - s = "-" + s; - } +func FmtString(f *Fmt, s string) *Fmt { f.pad(s); f.clearflags(); return f; } // float64 +func (f *Fmt) e64(a float64) *Fmt { + return FmtString(f, strconv.ftoa64(a, 'e', Prec(f, 6))); +} + func (f *Fmt) f64(a float64) *Fmt { - var negative bool; - var g float64; - var exp int; - if f.InfOrNan(a) { - return f; - } - negative, exp, g = unpack(a); - if exp > 19 || exp < -19 { // too big for this sloppy code - return f.e64(a); - } - prec := 6; - if f.prec_present { - prec = f.prec; - } - // prec is number of digits after decimal point - s := "NO"; - if exp >= 0 { - g *= pow10(exp); - gi := int64(g); - s = New().integer(gi, 10, true, &ldigits); - s = s + "."; - g -= float64(gi); - s = s + New().p(prec).integer(int64(g*pow10(prec) + .5), 10, true, &ldigits); - } else { - g *= pow10(prec + exp); - s = "0." + New().p(prec).integer(int64(g + .5), 10, true, &ldigits); - } - if negative { - s = "-" + s; - } - f.pad(s); - f.clearflags(); - return f; + return FmtString(f, strconv.ftoa64(a, 'f', Prec(f, 6))); } -// float64 func (f *Fmt) g64(a float64) *Fmt { - if f.InfOrNan(a) { - return f; - } - f1 := New(); - f2 := New(); - if f.wid_present { - f1.w(f.wid); - f2.w(f.wid); - } - if f.prec_present { - f1.p(f.prec); - f2.p(f.prec); - } - efmt := f1.e64(a).str(); - ffmt := f2.f64(a).str(); - // ffmt can return e in my bogus world; don't trim trailing 0s if so. - f_is_e := false; - for i := 0; i < len(ffmt); i++ { - if ffmt[i] == 'e' { - f_is_e = true; - break; - } - } - if !f_is_e { - // strip trailing zeros - l := len(ffmt); - for ffmt[l-1]=='0' { - l--; - } - ffmt = ffmt[0:l]; - } - if len(efmt) < len(ffmt) { - f.pad(efmt); - } else { - f.pad(ffmt); - } - f.clearflags(); - return f; + return FmtString(f, strconv.ftoa64(a, 'g', Prec(f, -1))); } -// float -func (x *Fmt) f32(a float32) *Fmt { - return x.f64(float64(a)) +func (f *Fmt) fb64(a float64) *Fmt { + return FmtString(f, strconv.ftoa64(a, 'b', 0)); } -func (x *Fmt) f(a float) *Fmt { - return x.f64(float64(a)) +// float32 +// cannot defer to float64 versions +// because it will get rounding wrong in corner cases. +func (f *Fmt) e32(a float32) *Fmt { + return FmtString(f, strconv.ftoa32(a, 'e', Prec(f, -1))); +} + +func (f *Fmt) f32(a float32) *Fmt { + return FmtString(f, strconv.ftoa32(a, 'f', Prec(f, 6))); +} + +func (f *Fmt) g32(a float32) *Fmt { + return FmtString(f, strconv.ftoa32(a, 'g', Prec(f, -1))); +} + +func (f *Fmt) fb32(a float32) *Fmt { + return FmtString(f, strconv.ftoa32(a, 'b', 0)); } // float -func (x *Fmt) e32(a float32) *Fmt { - return x.e64(float64(a)) +func (x *Fmt) f(a float) *Fmt { + if strconv.floatsize == 32 { + return x.f32(float32(a)) + } + return x.f64(float64(a)) } func (x *Fmt) e(a float) *Fmt { + if strconv.floatsize == 32 { + return x.e32(float32(a)) + } return x.e64(float64(a)) } -// float -func (x *Fmt) g32(a float32) *Fmt { +func (x *Fmt) g(a float) *Fmt { + if strconv.floatsize == 32 { + return x.g32(float32(a)) + } return x.g64(float64(a)) } -func (x *Fmt) g(a float) *Fmt { - return x.g64(float64(a)) +func (x *Fmt) fb(a float) *Fmt { + if strconv.floatsize == 32 { + return x.fb32(float32(a)) + } + return x.fb64(float64(a)) } diff --git a/src/lib/fmt/print.go b/src/lib/fmt/print.go index 8fa337f807..ce7a4f2d39 100644 --- a/src/lib/fmt/print.go +++ b/src/lib/fmt/print.go @@ -230,12 +230,24 @@ func getString(v reflect.Value) (val string, ok bool) { return "", false; } -func getFloat(v reflect.Value) (val float64, ok bool) { +func getFloat32(v reflect.Value) (val float32, ok bool) { switch v.Kind() { - case reflect.FloatKind: - return float64(v.(reflect.FloatValue).Get()), true; case reflect.Float32Kind: - return float64(v.(reflect.Float32Value).Get()), true; + return float32(v.(reflect.Float32Value).Get()), true; + case reflect.FloatKind: + if v.Type().Size()*8 == 32 { + return float32(v.(reflect.FloatValue).Get()), true; + } + } + return 0.0, false; +} + +func getFloat64(v reflect.Value) (val float64, ok bool) { + switch v.Kind() { + case reflect.FloatKind: + if v.Type().Size()*8 == 64 { + return float64(v.(reflect.FloatValue).Get()), true; + } case reflect.Float64Kind: return float64(v.(reflect.Float64Value).Get()), true; case reflect.Float80Kind: @@ -299,9 +311,20 @@ func (p *P) printField(field reflect.Value) (was_string bool) { case reflect.UintKind, reflect.Uint8Kind, reflect.Uint16Kind, reflect.Uint32Kind, reflect.Uint64Kind: v, signed, ok := getInt(field); s = p.fmt.ud64(uint64(v)).str(); - case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind, reflect.Float80Kind: - v, ok := getFloat(field); + case reflect.Float32Kind: + v, ok := getFloat32(field); + s = p.fmt.g32(v).str(); + case reflect.Float64Kind, reflect.Float80Kind: + v, ok := getFloat64(field); s = p.fmt.g64(v).str(); + case reflect.FloatKind: + if field.Type().Size()*8 == 32 { + v, ok := getFloat32(field); + s = p.fmt.g32(v).str(); + } else { + v, ok := getFloat64(field); + s = p.fmt.g64(v).str(); + } case reflect.StringKind: v, ok := getString(field); s = p.fmt.s(v).str(); @@ -400,6 +423,10 @@ func (p *P) doprintf(format string, v reflect.StructValue) { case 'b': if v, signed, ok := getInt(field); ok { s = p.fmt.b64(uint64(v)).str() // always unsigned + } else if v, ok := getFloat32(field); ok { + s = p.fmt.fb32(v).str() + } else if v, ok := getFloat64(field); ok { + s = p.fmt.fb64(v).str() } else { goto badtype } @@ -442,19 +469,25 @@ func (p *P) doprintf(format string, v reflect.StructValue) { // float case 'e': - if v, ok := getFloat(field); ok { + if v, ok := getFloat32(field); ok { + s = p.fmt.e32(v).str() + } else if v, ok := getFloat64(field); ok { s = p.fmt.e64(v).str() } else { goto badtype } case 'f': - if v, ok := getFloat(field); ok { + if v, ok := getFloat32(field); ok { + s = p.fmt.f32(v).str() + } else if v, ok := getFloat64(field); ok { s = p.fmt.f64(v).str() } else { goto badtype } case 'g': - if v, ok := getFloat(field); ok { + if v, ok := getFloat32(field); ok { + s = p.fmt.g32(v).str() + } else if v, ok := getFloat64(field); ok { s = p.fmt.g64(v).str() } else { goto badtype |
