Source file
src/strconv/ftoa.go
Documentation: strconv
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
47 func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
48 return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize))
49 }
50
51
52
53 func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte {
54 return genericFtoa(dst, f, fmt, prec, bitSize)
55 }
56
57 func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
58 var bits uint64
59 var flt *floatInfo
60 switch bitSize {
61 case 32:
62 bits = uint64(math.Float32bits(float32(val)))
63 flt = &float32info
64 case 64:
65 bits = math.Float64bits(val)
66 flt = &float64info
67 default:
68 panic("strconv: illegal AppendFloat/FormatFloat bitSize")
69 }
70
71 neg := bits>>(flt.expbits+flt.mantbits) != 0
72 exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
73 mant := bits & (uint64(1)<<flt.mantbits - 1)
74
75 switch exp {
76 case 1<<flt.expbits - 1:
77
78 var s string
79 switch {
80 case mant != 0:
81 s = "NaN"
82 case neg:
83 s = "-Inf"
84 default:
85 s = "+Inf"
86 }
87 return append(dst, s...)
88
89 case 0:
90
91 exp++
92
93 default:
94
95 mant |= uint64(1) << flt.mantbits
96 }
97 exp += flt.bias
98
99
100 if fmt == 'b' {
101 return fmtB(dst, neg, mant, exp, flt)
102 }
103 if fmt == 'x' || fmt == 'X' {
104 return fmtX(dst, prec, fmt, neg, mant, exp, flt)
105 }
106
107 if !optimize {
108 return bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
109 }
110
111 var digs decimalSlice
112 ok := false
113
114 shortest := prec < 0
115 if shortest {
116
117 var buf [32]byte
118 digs.d = buf[:]
119 ryuFtoaShortest(&digs, mant, exp-int(flt.mantbits), flt)
120 ok = true
121
122 switch fmt {
123 case 'e', 'E':
124 prec = max(digs.nd-1, 0)
125 case 'f':
126 prec = max(digs.nd-digs.dp, 0)
127 case 'g', 'G':
128 prec = digs.nd
129 }
130 } else if fmt != 'f' {
131
132 digits := prec
133 switch fmt {
134 case 'e', 'E':
135 digits++
136 case 'g', 'G':
137 if prec == 0 {
138 prec = 1
139 }
140 digits = prec
141 }
142 var buf [24]byte
143 if bitSize == 32 && digits <= 9 {
144 digs.d = buf[:]
145 ryuFtoaFixed32(&digs, uint32(mant), exp-int(flt.mantbits), digits)
146 ok = true
147 } else if digits <= 18 {
148 digs.d = buf[:]
149 ryuFtoaFixed64(&digs, mant, exp-int(flt.mantbits), digits)
150 ok = true
151 }
152 }
153 if !ok {
154 return bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
155 }
156 return formatDigits(dst, shortest, neg, digs, prec, fmt)
157 }
158
159
160 func bigFtoa(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
161 d := new(decimal)
162 d.Assign(mant)
163 d.Shift(exp - int(flt.mantbits))
164 var digs decimalSlice
165 shortest := prec < 0
166 if shortest {
167 roundShortest(d, mant, exp, flt)
168 digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp}
169
170 switch fmt {
171 case 'e', 'E':
172 prec = digs.nd - 1
173 case 'f':
174 prec = max(digs.nd-digs.dp, 0)
175 case 'g', 'G':
176 prec = digs.nd
177 }
178 } else {
179
180 switch fmt {
181 case 'e', 'E':
182 d.Round(prec + 1)
183 case 'f':
184 d.Round(d.dp + prec)
185 case 'g', 'G':
186 if prec == 0 {
187 prec = 1
188 }
189 d.Round(prec)
190 }
191 digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp}
192 }
193 return formatDigits(dst, shortest, neg, digs, prec, fmt)
194 }
195
196 func formatDigits(dst []byte, shortest bool, neg bool, digs decimalSlice, prec int, fmt byte) []byte {
197 switch fmt {
198 case 'e', 'E':
199 return fmtE(dst, neg, digs, prec, fmt)
200 case 'f':
201 return fmtF(dst, neg, digs, prec)
202 case 'g', 'G':
203
204 eprec := prec
205 if eprec > digs.nd && digs.nd >= digs.dp {
206 eprec = digs.nd
207 }
208
209
210
211 if shortest {
212 eprec = 6
213 }
214 exp := digs.dp - 1
215 if exp < -4 || exp >= eprec {
216 if prec > digs.nd {
217 prec = digs.nd
218 }
219 return fmtE(dst, neg, digs, prec-1, fmt+'e'-'g')
220 }
221 if prec > digs.dp {
222 prec = digs.nd
223 }
224 return fmtF(dst, neg, digs, max(prec-digs.dp, 0))
225 }
226
227
228 return append(dst, '%', fmt)
229 }
230
231
232
233 func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
234
235 if mant == 0 {
236 d.nd = 0
237 return
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254 minexp := flt.bias + 1
255 if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
256
257 return
258 }
259
260
261
262
263 upper := new(decimal)
264 upper.Assign(mant*2 + 1)
265 upper.Shift(exp - int(flt.mantbits) - 1)
266
267
268
269
270
271
272
273 var mantlo uint64
274 var explo int
275 if mant > 1<<flt.mantbits || exp == minexp {
276 mantlo = mant - 1
277 explo = exp
278 } else {
279 mantlo = mant*2 - 1
280 explo = exp - 1
281 }
282 lower := new(decimal)
283 lower.Assign(mantlo*2 + 1)
284 lower.Shift(explo - int(flt.mantbits) - 1)
285
286
287
288
289 inclusive := mant%2 == 0
290
291
292
293
294
295
296
297
298
299
300
301
302 var upperdelta uint8
303
304
305
306 for ui := 0; ; ui++ {
307
308
309
310 mi := ui - upper.dp + d.dp
311 if mi >= d.nd {
312 break
313 }
314 li := ui - upper.dp + lower.dp
315 l := byte('0')
316 if li >= 0 && li < lower.nd {
317 l = lower.d[li]
318 }
319 m := byte('0')
320 if mi >= 0 {
321 m = d.d[mi]
322 }
323 u := byte('0')
324 if ui < upper.nd {
325 u = upper.d[ui]
326 }
327
328
329
330
331 okdown := l != m || inclusive && li+1 == lower.nd
332
333 switch {
334 case upperdelta == 0 && m+1 < u:
335
336
337
338 upperdelta = 2
339 case upperdelta == 0 && m != u:
340
341
342
343 upperdelta = 1
344 case upperdelta == 1 && (m != '9' || u != '0'):
345
346
347
348 upperdelta = 2
349 }
350
351
352 okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd)
353
354
355
356 switch {
357 case okdown && okup:
358 d.Round(mi + 1)
359 return
360 case okdown:
361 d.RoundDown(mi + 1)
362 return
363 case okup:
364 d.RoundUp(mi + 1)
365 return
366 }
367 }
368 }
369
370 type decimalSlice struct {
371 d []byte
372 nd, dp int
373 neg bool
374 }
375
376
377 func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
378
379 if neg {
380 dst = append(dst, '-')
381 }
382
383
384 ch := byte('0')
385 if d.nd != 0 {
386 ch = d.d[0]
387 }
388 dst = append(dst, ch)
389
390
391 if prec > 0 {
392 dst = append(dst, '.')
393 i := 1
394 m := min(d.nd, prec+1)
395 if i < m {
396 dst = append(dst, d.d[i:m]...)
397 i = m
398 }
399 for ; i <= prec; i++ {
400 dst = append(dst, '0')
401 }
402 }
403
404
405 dst = append(dst, fmt)
406 exp := d.dp - 1
407 if d.nd == 0 {
408 exp = 0
409 }
410 if exp < 0 {
411 ch = '-'
412 exp = -exp
413 } else {
414 ch = '+'
415 }
416 dst = append(dst, ch)
417
418
419 switch {
420 case exp < 10:
421 dst = append(dst, '0', byte(exp)+'0')
422 case exp < 100:
423 dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
424 default:
425 dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0')
426 }
427
428 return dst
429 }
430
431
432 func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte {
433
434 if neg {
435 dst = append(dst, '-')
436 }
437
438
439 if d.dp > 0 {
440 m := min(d.nd, d.dp)
441 dst = append(dst, d.d[:m]...)
442 for ; m < d.dp; m++ {
443 dst = append(dst, '0')
444 }
445 } else {
446 dst = append(dst, '0')
447 }
448
449
450 if prec > 0 {
451 dst = append(dst, '.')
452 for i := 0; i < prec; i++ {
453 ch := byte('0')
454 if j := d.dp + i; 0 <= j && j < d.nd {
455 ch = d.d[j]
456 }
457 dst = append(dst, ch)
458 }
459 }
460
461 return dst
462 }
463
464
465 func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
466
467 if neg {
468 dst = append(dst, '-')
469 }
470
471
472 dst, _ = formatBits(dst, mant, 10, false, true)
473
474
475 dst = append(dst, 'p')
476
477
478 exp -= int(flt.mantbits)
479 if exp >= 0 {
480 dst = append(dst, '+')
481 }
482 dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true)
483
484 return dst
485 }
486
487
488 func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
489 if mant == 0 {
490 exp = 0
491 }
492
493
494 mant <<= 60 - flt.mantbits
495 for mant != 0 && mant&(1<<60) == 0 {
496 mant <<= 1
497 exp--
498 }
499
500
501 if prec >= 0 && prec < 15 {
502 shift := uint(prec * 4)
503 extra := (mant << shift) & (1<<60 - 1)
504 mant >>= 60 - shift
505 if extra|(mant&1) > 1<<59 {
506 mant++
507 }
508 mant <<= 60 - shift
509 if mant&(1<<61) != 0 {
510
511 mant >>= 1
512 exp++
513 }
514 }
515
516 hex := lowerhex
517 if fmt == 'X' {
518 hex = upperhex
519 }
520
521
522 if neg {
523 dst = append(dst, '-')
524 }
525 dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1))
526
527
528 mant <<= 4
529 if prec < 0 && mant != 0 {
530 dst = append(dst, '.')
531 for mant != 0 {
532 dst = append(dst, hex[(mant>>60)&15])
533 mant <<= 4
534 }
535 } else if prec > 0 {
536 dst = append(dst, '.')
537 for i := 0; i < prec; i++ {
538 dst = append(dst, hex[(mant>>60)&15])
539 mant <<= 4
540 }
541 }
542
543
544 ch := byte('P')
545 if fmt == lower(fmt) {
546 ch = 'p'
547 }
548 dst = append(dst, ch)
549 if exp < 0 {
550 ch = '-'
551 exp = -exp
552 } else {
553 ch = '+'
554 }
555 dst = append(dst, ch)
556
557
558 switch {
559 case exp < 100:
560 dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
561 case exp < 1000:
562 dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
563 default:
564 dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
565 }
566
567 return dst
568 }
569
570 func min(a, b int) int {
571 if a < b {
572 return a
573 }
574 return b
575 }
576
577 func max(a, b int) int {
578 if a > b {
579 return a
580 }
581 return b
582 }
583
View as plain text