]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/gc: use approx. float formatting in error messages
authorRobert Griesemer <gri@golang.org>
Sat, 4 Apr 2015 00:50:37 +0000 (17:50 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 7 Apr 2015 23:01:01 +0000 (23:01 +0000)
For very out-of-range floating-point constants (1e100000000),
precise formatting of the offending value for error messages
is not needed and potentially extremely slow.

This change resurrects an adjusted variant of the original code
which uses float64 formatting in the common case (in-range values),
and a fast manual approximation for out-of-range values.

Change-Id: I2f6e53040929b8bf924dac4bb27c4d811ede48e2
Reviewed-on: https://go-review.googlesource.com/8470
Reviewed-by: Alan Donovan <adonovan@google.com>
src/cmd/internal/gc/mparith3.go

index d1ae41dd740f9c8f4d014b2f23cbed06f2007726..88ab0e74135fd34e70e1af0bdf8781cece0d1886 100644 (file)
@@ -5,6 +5,7 @@
 package gc
 
 import (
+       "cmd/internal/gc/big"
        "cmd/internal/obj"
        "fmt"
        "math"
@@ -184,8 +185,47 @@ func mpatoflt(a *Mpflt, as string) {
 }
 
 func Fconv(fvp *Mpflt, flag int) string {
-       if flag&obj.FmtSharp != 0 {
-               return fvp.Val.Format('g', 6)
+       if flag&obj.FmtSharp == 0 {
+               return fvp.Val.Format('b', 0)
        }
-       return fvp.Val.Format('b', 0)
+
+       // use decimal format for error messages
+
+       // determine sign
+       f := &fvp.Val
+       var sign string
+       if fvp.Val.Signbit() {
+               sign = "-"
+               f = new(big.Float).Abs(f)
+       } else if flag&obj.FmtSign != 0 {
+               sign = "+"
+       }
+
+       // Use fmt formatting if in float64 range (common case).
+       if x, _ := f.Float64(); !math.IsInf(x, 0) {
+               return fmt.Sprintf("%s%.6g", sign, x)
+       }
+
+       // Out of float64 range. Do approximate manual to decimal
+       // conversion to avoid precise but possibly slow Float
+       // formatting. The exponent is > 0 since a negative out-
+       // of-range exponent would have underflowed and led to 0.
+       // f = mant * 2**exp
+       var mant big.Float
+       exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0
+
+       // approximate float64 mantissa m and decimal exponent d
+       // f ~ m * 10**d
+       m, _ := mant.Float64()            // 0.5 <= m < 1.0
+       d := exp * (math.Ln2 / math.Ln10) // log_10(2)
+
+       // adjust m for truncated (integer) decimal exponent e
+       e := int64(d)
+       m *= math.Pow(10, d-float64(e))
+       for m >= 10 {
+               m /= 10
+               e++
+       }
+
+       return fmt.Sprintf("%s%.5fe+%d", sign, m, e)
 }