|
5 | 5 | package gc
|
6 | 6 |
|
7 | 7 | import (
|
| 8 | + "cmd/internal/gc/big" |
8 | 9 | "cmd/internal/obj"
|
9 | 10 | "fmt"
|
10 | 11 | "math"
|
@@ -184,8 +185,47 @@ func mpatoflt(a *Mpflt, as string) {
|
184 | 185 | }
|
185 | 186 |
|
186 | 187 | 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) |
189 | 190 | }
|
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) |
191 | 231 | }
|
0 commit comments