Skip to content

Commit bb418a5

Browse files
committed
cmd/internal/gc: use approx. float formatting in error messages
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 <[email protected]>
1 parent b643684 commit bb418a5

File tree

1 file changed

+43
-3
lines changed

1 file changed

+43
-3
lines changed

src/cmd/internal/gc/mparith3.go

+43-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package gc
66

77
import (
8+
"cmd/internal/gc/big"
89
"cmd/internal/obj"
910
"fmt"
1011
"math"
@@ -184,8 +185,47 @@ func mpatoflt(a *Mpflt, as string) {
184185
}
185186

186187
func Fconv(fvp *Mpflt, flag int) string {
187-
if flag&obj.FmtSharp != 0 {
188-
return fvp.Val.Format('g', 6)
188+
if flag&obj.FmtSharp == 0 {
189+
return fvp.Val.Format('b', 0)
189190
}
190-
return fvp.Val.Format('b', 0)
191+
192+
// use decimal format for error messages
193+
194+
// determine sign
195+
f := &fvp.Val
196+
var sign string
197+
if fvp.Val.Signbit() {
198+
sign = "-"
199+
f = new(big.Float).Abs(f)
200+
} else if flag&obj.FmtSign != 0 {
201+
sign = "+"
202+
}
203+
204+
// Use fmt formatting if in float64 range (common case).
205+
if x, _ := f.Float64(); !math.IsInf(x, 0) {
206+
return fmt.Sprintf("%s%.6g", sign, x)
207+
}
208+
209+
// Out of float64 range. Do approximate manual to decimal
210+
// conversion to avoid precise but possibly slow Float
211+
// formatting. The exponent is > 0 since a negative out-
212+
// of-range exponent would have underflowed and led to 0.
213+
// f = mant * 2**exp
214+
var mant big.Float
215+
exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0
216+
217+
// approximate float64 mantissa m and decimal exponent d
218+
// f ~ m * 10**d
219+
m, _ := mant.Float64() // 0.5 <= m < 1.0
220+
d := exp * (math.Ln2 / math.Ln10) // log_10(2)
221+
222+
// adjust m for truncated (integer) decimal exponent e
223+
e := int64(d)
224+
m *= math.Pow(10, d-float64(e))
225+
for m >= 10 {
226+
m /= 10
227+
e++
228+
}
229+
230+
return fmt.Sprintf("%s%.5fe+%d", sign, m, e)
191231
}

0 commit comments

Comments
 (0)