diff options
| author | Russ Cox <rsc@golang.org> | 2008-11-17 12:34:03 -0800 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2008-11-17 12:34:03 -0800 |
| commit | 079c00a475d11f71a69fe848dd67e8fe34ac88a8 (patch) | |
| tree | aeb58cc993873dadfe1a2adbc63521879b2dd66a /src/lib/fmt/format.go | |
| parent | f333f4685cc667dda0be6ecd5500ff8fa10f4a2a (diff) | |
| download | go-079c00a475d11f71a69fe848dd67e8fe34ac88a8.tar.xz | |
correctly rounded floating-point conversions
in new package strconv.
move atoi etc to strconv too.
update fmt, etc to use strconv.
R=r
DELTA=2232 (1691 added, 424 deleted, 117 changed)
OCL=19286
CL=19380
Diffstat (limited to 'src/lib/fmt/format.go')
| -rw-r--r-- | src/lib/fmt/format.go | 245 |
1 files changed, 51 insertions, 194 deletions
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)) } |
