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