aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/strconv/ftoa.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/strconv/ftoa.go')
-rw-r--r--libgo/go/strconv/ftoa.go78
1 files changed, 51 insertions, 27 deletions
diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go
index f4434fd..8eefbee 100644
--- a/libgo/go/strconv/ftoa.go
+++ b/libgo/go/strconv/ftoa.go
@@ -98,29 +98,43 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
return fmtB(dst, neg, mant, exp, flt)
}
- // Create exact decimal representation.
- // The shift is exp - flt.mantbits because mant is a 1-bit integer
- // followed by a flt.mantbits fraction, and we are treating it as
- // a 1+flt.mantbits-bit integer.
- d := new(decimal)
- d.Assign(mant)
- d.Shift(exp - int(flt.mantbits))
-
- // Round appropriately.
// Negative precision means "only as much as needed to be exact."
- shortest := false
- if prec < 0 {
- shortest = true
- roundShortest(d, mant, exp, flt)
- switch fmt {
- case 'e', 'E':
- prec = d.nd - 1
- case 'f':
- prec = max(d.nd-d.dp, 0)
- case 'g', 'G':
- prec = d.nd
+ shortest := prec < 0
+
+ d := new(decimal)
+ if shortest {
+ ok := false
+ if optimize && bitSize == 64 {
+ // Try Grisu3 algorithm.
+ f := new(extFloat)
+ lower, upper := f.AssignComputeBounds(val)
+ ok = f.ShortestDecimal(d, &lower, &upper)
+ }
+ if !ok {
+ // Create exact decimal representation.
+ // The shift is exp - flt.mantbits because mant is a 1-bit integer
+ // followed by a flt.mantbits fraction, and we are treating it as
+ // a 1+flt.mantbits-bit integer.
+ d.Assign(mant)
+ d.Shift(exp - int(flt.mantbits))
+ roundShortest(d, mant, exp, flt)
+ }
+ // Precision for shortest representation mode.
+ if prec < 0 {
+ switch fmt {
+ case 'e', 'E':
+ prec = d.nd - 1
+ case 'f':
+ prec = max(d.nd-d.dp, 0)
+ case 'g', 'G':
+ prec = d.nd
+ }
}
} else {
+ // Create exact decimal representation.
+ d.Assign(mant)
+ d.Shift(exp - int(flt.mantbits))
+ // Round appropriately.
switch fmt {
case 'e', 'E':
d.Round(prec + 1)
@@ -178,15 +192,26 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
return
}
- // TODO(rsc): Unless exp == minexp, if the number of digits in d
- // is less than 17, it seems likely that it would be
- // the shortest possible number already. So maybe we can
- // bail out without doing the extra multiprecision math here.
-
// Compute upper and lower such that any decimal number
// between upper and lower (possibly inclusive)
// will round to the original floating point number.
+ // We may see at once that the number is already shortest.
+ //
+ // Suppose d is not denormal, so that 2^exp <= d < 10^dp.
+ // The closest shorter number is at least 10^(dp-nd) away.
+ // The lower/upper bounds computed below are at distance
+ // at most 2^(exp-mantbits).
+ //
+ // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits),
+ // or equivalently log2(10)*(dp-nd) > exp-mantbits.
+ // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
+ minexp := flt.bias + 1 // minimum possible exponent
+ if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
+ // The number is already shortest.
+ return
+ }
+
// d = mant << (exp - mantbits)
// Next highest floating point number is mant+1 << exp-mantbits.
// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
@@ -200,7 +225,6 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
// in which case the next lowest is mant*2-1 << exp-mantbits-1.
// Either way, call it mantlo << explo-mantbits.
// Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
- minexp := flt.bias + 1 // minimum possible exponent
var mantlo uint64
var explo int
if mant > 1<<flt.mantbits || exp == minexp {
@@ -241,7 +265,7 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
// Okay to round up if upper has a different digit and
// either upper is inclusive or upper is bigger than the result of rounding up.
- okup := m != u && (inclusive || i+1 < upper.nd)
+ okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)
// If it's okay to do either, then round to the nearest one.
// If it's okay to do only one, do it.