1
2
3
4
5
6
7
8
9
10
11 package strconv
12
13 import "math"
14
15
16 type floatInfo struct {
17 mantbits uint
18 expbits uint
19 bias int
20 }
21
22 var float32info = floatInfo{23, 8, -127}
23 var float64info = floatInfo{52, 11, -1023}
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 func Ftoa32(f float32, fmt byte, prec int) string {
47 return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info)
48 }
49
50
51 func Ftoa64(f float64, fmt byte, prec int) string {
52 return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
53 }
54
55
56
57
58
59 func FtoaN(f float64, fmt byte, prec int, n int) string {
60 if n == 32 {
61 return Ftoa32(float32(f), fmt, prec)
62 }
63 return Ftoa64(f, fmt, prec)
64 }
65
66 func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
67 neg := bits>>(flt.expbits+flt.mantbits) != 0
68 exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
69 mant := bits & (uint64(1)<<flt.mantbits - 1)
70
71 switch exp {
72 case 1<<flt.expbits - 1:
73
74 if mant != 0 {
75 return "NaN"
76 }
77 if neg {
78 return "-Inf"
79 }
80 return "+Inf"
81
82 case 0:
83
84 exp++
85
86 default:
87
88 mant |= uint64(1) << flt.mantbits
89 }
90 exp += flt.bias
91
92
93 if fmt == 'b' {
94 return fmtB(neg, mant, exp, flt)
95 }
96
97
98
99
100
101 d := newDecimal(mant).Shift(exp - int(flt.mantbits))
102
103
104
105 shortest := false
106 if prec < 0 {
107 shortest = true
108 roundShortest(d, mant, exp, flt)
109 switch fmt {
110 case 'e', 'E':
111 prec = d.nd - 1
112 case 'f':
113 prec = max(d.nd-d.dp, 0)
114 case 'g', 'G':
115 prec = d.nd
116 }
117 } else {
118 switch fmt {
119 case 'e', 'E':
120 d.Round(prec + 1)
121 case 'f':
122 d.Round(d.dp + prec)
123 case 'g', 'G':
124 if prec == 0 {
125 prec = 1
126 }
127 d.Round(prec)
128 }
129 }
130
131 switch fmt {
132 case 'e', 'E':
133 return fmtE(neg, d, prec, fmt)
134 case 'f':
135 return fmtF(neg, d, prec)
136 case 'g', 'G':
137
138 eprec := prec
139 if eprec > d.nd && d.nd >= d.dp {
140 eprec = d.nd
141 }
142
143
144
145 if shortest {
146 eprec = 6
147 }
148 exp := d.dp - 1
149 if exp < -4 || exp >= eprec {
150 if prec > d.nd {
151 prec = d.nd
152 }
153 return fmtE(neg, d, prec-1, fmt+'e'-'g')
154 }
155 if prec > d.dp {
156 prec = d.nd
157 }
158 return fmtF(neg, d, max(prec-d.dp, 0))
159 }
160
161 return "%" + string(fmt)
162 }
163
164
165
166
167 func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
168
169 if mant == 0 {
170 d.nd = 0
171 return
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186 upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1)
187
188
189
190
191
192
193
194 minexp := flt.bias + 1
195 var mantlo uint64
196 var explo int
197 if mant > 1<<flt.mantbits || exp == minexp {
198 mantlo = mant - 1
199 explo = exp
200 } else {
201 mantlo = mant*2 - 1
202 explo = exp - 1
203 }
204 lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1)
205
206
207
208
209 inclusive := mant%2 == 0
210
211
212
213 for i := 0; i < d.nd; i++ {
214 var l, m, u byte
215 if i < lower.nd {
216 l = lower.d[i]
217 } else {
218 l = '0'
219 }
220 m = d.d[i]
221 if i < upper.nd {
222 u = upper.d[i]
223 } else {
224 u = '0'
225 }
226
227
228
229 okdown := l != m || (inclusive && l == m && i+1 == lower.nd)
230
231
232
233 okup := m != u && (inclusive || i+1 < upper.nd)
234
235
236
237 switch {
238 case okdown && okup:
239 d.Round(i + 1)
240 return
241 case okdown:
242 d.RoundDown(i + 1)
243 return
244 case okup:
245 d.RoundUp(i + 1)
246 return
247 }
248 }
249 }
250
251
252 func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
253 buf := make([]byte, 3+max(prec, 0)+30)
254 w := 0
255
256
257 if neg {
258 buf[w] = '-'
259 w++
260 }
261
262
263 if d.nd == 0 {
264 buf[w] = '0'
265 } else {
266 buf[w] = d.d[0]
267 }
268 w++
269
270
271 if prec > 0 {
272 buf[w] = '.'
273 w++
274 for i := 0; i < prec; i++ {
275 if 1+i < d.nd {
276 buf[w] = d.d[1+i]
277 } else {
278 buf[w] = '0'
279 }
280 w++
281 }
282 }
283
284
285 buf[w] = fmt
286 w++
287 exp := d.dp - 1
288 if d.nd == 0 {
289 exp = 0
290 }
291 if exp < 0 {
292 buf[w] = '-'
293 exp = -exp
294 } else {
295 buf[w] = '+'
296 }
297 w++
298
299
300
301 n := 0
302 for e := exp; e > 0; e /= 10 {
303 n++
304 }
305
306 for i := n; i < 2; i++ {
307 buf[w] = '0'
308 w++
309 }
310
311 w += n
312 n = 0
313 for e := exp; e > 0; e /= 10 {
314 n++
315 buf[w-n] = byte(e%10 + '0')
316 }
317
318 return string(buf[0:w])
319 }
320
321
322 func fmtF(neg bool, d *decimal, prec int) string {
323 buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
324 w := 0
325
326
327 if neg {
328 buf[w] = '-'
329 w++
330 }
331
332
333 if d.dp > 0 {
334 var i int
335 for i = 0; i < d.dp && i < d.nd; i++ {
336 buf[w] = d.d[i]
337 w++
338 }
339 for ; i < d.dp; i++ {
340 buf[w] = '0'
341 w++
342 }
343 } else {
344 buf[w] = '0'
345 w++
346 }
347
348
349 if prec > 0 {
350 buf[w] = '.'
351 w++
352 for i := 0; i < prec; i++ {
353 if d.dp+i < 0 || d.dp+i >= d.nd {
354 buf[w] = '0'
355 } else {
356 buf[w] = d.d[d.dp+i]
357 }
358 w++
359 }
360 }
361
362 return string(buf[0:w])
363 }
364
365
366 func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
367 var buf [50]byte
368 w := len(buf)
369 exp -= int(flt.mantbits)
370 esign := byte('+')
371 if exp < 0 {
372 esign = '-'
373 exp = -exp
374 }
375 n := 0
376 for exp > 0 || n < 1 {
377 n++
378 w--
379 buf[w] = byte(exp%10 + '0')
380 exp /= 10
381 }
382 w--
383 buf[w] = esign
384 w--
385 buf[w] = 'p'
386 n = 0
387 for mant > 0 || n < 1 {
388 n++
389 w--
390 buf[w] = byte(mant%10 + '0')
391 mant /= 10
392 }
393 if neg {
394 w--
395 buf[w] = '-'
396 }
397 return string(buf[w:])
398 }
399
400 func max(a, b int) int {
401 if a > b {
402 return a
403 }
404 return b
405 }