We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent 6e165b4 commit dd839f1Copy full SHA for dd839f1
src/internal/strconv/ftoa.go
@@ -146,28 +146,38 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
146
return formatDigits(dst, shortest, neg, digs, prec, fmt)
147
}
148
149
- // TODO figure out when we can use fast code for f
150
- if fmt != 'f' {
151
- // Fixed number of digits.
152
- digits := prec
153
- switch fmt {
154
- case 'e', 'E':
155
- digits++
156
- case 'g', 'G':
157
- if prec == 0 {
158
- prec = 1
159
- }
160
- digits = prec
161
- default:
162
- // Invalid mode.
163
- digits = 1
+ // Fixed number of digits.
+ digits := prec
+ switch fmt {
+ case 'f':
+ // %f precision specifies digits after the decimal point.
+ // Estimate an upper bound on the total number of digits needed.
+ // ftoaFixed will shorten as needed according to prec.
+ if exp >= 0 {
+ digits = 1 + mulLog10_2(1+exp) + prec
+ } else {
+ digits = 1 + prec - mulLog10_2(-exp)
164
165
- if digits <= 18 {
+ case 'e', 'E':
+ digits++
+ case 'g', 'G':
+ if prec == 0 {
+ prec = 1
166
+ }
167
+ digits = prec
168
+ default:
169
+ // Invalid mode.
170
+ digits = 1
171
172
+ if digits <= 18 {
173
+ // digits <= 0 happens for %f on very small numbers
174
+ // and means that we're guaranteed to print all zeros.
175
+ if digits > 0 {
176
var buf [24]byte
177
digs.d = buf[:]
- fixedFtoa(&digs, mant, exp-int(flt.mantbits), digits)
- return formatDigits(dst, false, neg, digs, prec, fmt)
178
+ fixedFtoa(&digs, mant, exp-int(flt.mantbits), digits, prec, fmt)
179
180
+ return formatDigits(dst, false, neg, digs, prec, fmt)
181
182
183
return bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
src/internal/strconv/ftoa_test.go
@@ -42,6 +42,29 @@ var ftoatests = []ftoaTest{
42
{2000000, 'g', -1, "2e+06"},
43
{1e10, 'g', -1, "1e+10"},
44
45
+ // f conversion basic cases
46
+ {12345, 'f', 2, "12345.00"},
47
+ {1234.5, 'f', 2, "1234.50"},
48
+ {123.45, 'f', 2, "123.45"},
49
+ {12.345, 'f', 2, "12.35"},
50
+ {1.2345, 'f', 2, "1.23"},
51
+ {0.12345, 'f', 2, "0.12"},
52
+ {0.12945, 'f', 2, "0.13"},
53
+ {0.012345, 'f', 2, "0.01"},
54
+ {0.015, 'f', 2, "0.01"},
55
+ {0.016, 'f', 2, "0.02"},
56
+ {0.0052345, 'f', 2, "0.01"},
57
+ {0.0012345, 'f', 2, "0.00"},
58
+ {0.00012345, 'f', 2, "0.00"},
59
+ {0.000012345, 'f', 2, "0.00"},
60
+
61
+ {0.996644984, 'f', 6, "0.996645"},
62
+ {0.996644984, 'f', 5, "0.99664"},
63
+ {0.996644984, 'f', 4, "0.9966"},
64
+ {0.996644984, 'f', 3, "0.997"},
65
+ {0.996644984, 'f', 2, "1.00"},
66
+ {0.996644984, 'f', 1, "1.0"},
67
68
// g conversion and zero suppression
69
{400, 'g', 2, "4e+02"},
70
{40, 'g', 2, "40"},
src/internal/strconv/ftoafixed.go
@@ -13,7 +13,9 @@ var uint64pow10 = [...]uint64{
13
14
// fixedFtoa formats a number of decimal digits of mant*(2^exp) into d,
15
// where mant > 0 and 1 ≤ digits ≤ 18.
16
-func fixedFtoa(d *decimalSlice, mant uint64, exp, digits int) {
+// If fmt == 'f', digits is a conservative overestimate, and the final
17
+// number of digits is prec past the decimal point.
18
+func fixedFtoa(d *decimalSlice, mant uint64, exp, digits, prec int, fmt byte) {
19
// The strategy here is to multiply (mant * 2^exp) by a power of 10
20
// to make the resulting integer be the number of digits we want.
21
//
@@ -133,6 +135,28 @@ func fixedFtoa(d *decimalSlice, mant uint64, exp, digits int) {
133
135
d.dp++
134
136
137
138
+ // If this is %.*f we may have overestimated the digits needed.
139
+ // Now that we know where the decimal point is,
140
+ // trim to the actual number of digits, which is d.dp+prec.
141
+ if fmt == 'f' && digits != d.dp+prec {
142
+ for digits > d.dp+prec {
143
+ var r uint
144
+ dm, r = dm/10, uint(dm%10)
145
+ dt |= bool2uint(r != 0)
+ digits--
+ // Dropping those digits can create a new leftmost
+ // non-zero digit, like if we are formatting %.1f and
+ // convert 0.09 -> 0.1. Detect and adjust for that.
+ if digits <= 0 {
+ d.dp++
+ max = uint64pow10[digits] << 1
// Round and shift away rounding bit.
// We want to round up when
// (a) the fractional part is > 0.5 (dm&1 != 0 and dt == 1)
@@ -148,9 +172,13 @@ func fixedFtoa(d *decimalSlice, mant uint64, exp, digits int) {
// Format digits into d.
- formatBase10(d.d[:digits], dm)
- d.nd = digits
- for d.d[d.nd-1] == '0' {
- d.nd--
+ if dm != 0 {
+ if formatBase10(d.d[:digits], dm) != 0 {
+ panic("formatBase10")
+ d.nd = digits
+ for d.d[d.nd-1] == '0' {
+ d.nd--
184
0 commit comments