Source file
src/strconv/ftoa.go
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 }
377
378
379 func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
380
381 if neg {
382 dst = append(dst, '-')
383 }
384
385
386 ch := byte('0')
387 if d.nd != 0 {
388 ch = d.d[0]
389 }
390 dst = append(dst, ch)
391
392
393 if prec > 0 {
394 dst = append(dst, '.')
395 i := 1
396 m := min(d.nd, prec+1)
397 if i < m {
398 dst = append(dst, d.d[i:m]...)
399 i = m
400 }
401 for ; i <= prec; i++ {
402 dst = append(dst, '0')
403 }
404 }
405
406
407 dst = append(dst, fmt)
408 exp := d.dp - 1
409 if d.nd == 0 {
410 exp = 0
411 }
412 if exp < 0 {
413 ch = '-'
414 exp = -exp
415 } else {
416 ch = '+'
417 }
418 dst = append(dst, ch)
419
420
421 switch {
422 case exp < 10:
423 dst = append(dst, '0', byte(exp)+'0')
424 case exp < 100:
425 dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
426 default:
427 dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0')
428 }
429
430 return dst
431 }
432
433
434 func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte {
435
436 if neg {
437 dst = append(dst, '-')
438 }
439
440
441 if d.dp > 0 {
442 m := min(d.nd, d.dp)
443 dst = append(dst, d.d[:m]...)
444 for ; m < d.dp; m++ {
445 dst = append(dst, '0')
446 }
447 } else {
448 dst = append(dst, '0')
449 }
450
451
452 if prec > 0 {
453 dst = append(dst, '.')
454 for i := 0; i < prec; i++ {
455 ch := byte('0')
456 if j := d.dp + i; 0 <= j && j < d.nd {
457 ch = d.d[j]
458 }
459 dst = append(dst, ch)
460 }
461 }
462
463 return dst
464 }
465
466
467 func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
468
469 if neg {
470 dst = append(dst, '-')
471 }
472
473
474 dst, _ = formatBits(dst, mant, 10, false, true)
475
476
477 dst = append(dst, 'p')
478
479
480 exp -= int(flt.mantbits)
481 if exp >= 0 {
482 dst = append(dst, '+')
483 }
484 dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true)
485
486 return dst
487 }
488
489
490 func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
491 if mant == 0 {
492 exp = 0
493 }
494
495
496 mant <<= 60 - flt.mantbits
497 for mant != 0 && mant&(1<<60) == 0 {
498 mant <<= 1
499 exp--
500 }
501
502
503 if prec >= 0 && prec < 15 {
504 shift := uint(prec * 4)
505 extra := (mant << shift) & (1<<60 - 1)
506 mant >>= 60 - shift
507 if extra|(mant&1) > 1<<59 {
508 mant++
509 }
510 mant <<= 60 - shift
511 if mant&(1<<61) != 0 {
512
513 mant >>= 1
514 exp++
515 }
516 }
517
518 hex := lowerhex
519 if fmt == 'X' {
520 hex = upperhex
521 }
522
523
524 if neg {
525 dst = append(dst, '-')
526 }
527 dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1))
528
529
530 mant <<= 4
531 if prec < 0 && mant != 0 {
532 dst = append(dst, '.')
533 for mant != 0 {
534 dst = append(dst, hex[(mant>>60)&15])
535 mant <<= 4
536 }
537 } else if prec > 0 {
538 dst = append(dst, '.')
539 for i := 0; i < prec; i++ {
540 dst = append(dst, hex[(mant>>60)&15])
541 mant <<= 4
542 }
543 }
544
545
546 ch := byte('P')
547 if fmt == lower(fmt) {
548 ch = 'p'
549 }
550 dst = append(dst, ch)
551 if exp < 0 {
552 ch = '-'
553 exp = -exp
554 } else {
555 ch = '+'
556 }
557 dst = append(dst, ch)
558
559
560 switch {
561 case exp < 100:
562 dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
563 case exp < 1000:
564 dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
565 default:
566 dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
567 }
568
569 return dst
570 }
571
View as plain text