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