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