1
2
3
4
5
6
7
8
9
10
11 package strconv
12
13 import (
14 "math/bits"
15 "unsafe"
16 )
17
18 const (
19 lowerhex = "0123456789abcdef"
20 upperhex = "0123456789ABCDEF"
21 )
22
23 const (
24 float32MantBits = 23
25 float32ExpBits = 8
26 float32Bias = -127
27 float32MinExp = -189
28
29 float64MantBits = 52
30 float64ExpBits = 11
31 float64Bias = -1023
32 float64MinExp = -1085
33 )
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
60 if bitSize == 32 {
61 return string(ftoa32(make([]byte, 0, max(prec+4, 24)), float32(f), fmt, prec))
62 }
63 if bitSize == 64 {
64 return string(ftoa64(make([]byte, 0, max(prec+4, 24)), f, fmt, prec))
65 }
66 panic("strconv: illegal FormatFloat bitSize")
67 }
68
69
70
71 func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte {
72 if bitSize == 32 {
73 return ftoa32(dst, float32(f), fmt, prec)
74 }
75 if bitSize == 64 {
76 return ftoa64(dst, f, fmt, prec)
77 }
78 panic("strconv: illegal AppendFloat bitSize")
79 }
80
81
82
83
84
85
86
87 func ftoa32(dst []byte, val float32, fmt byte, prec int) []byte {
88 type F = float32
89 var b uint64
90 var expBits, mantBits, bias int
91 switch 8 * unsafe.Sizeof(val) {
92 case 32:
93 b = uint64(float32bits(float32(val)))
94 expBits = float32ExpBits
95 mantBits = float32MantBits
96 bias = float32Bias
97 case 64:
98 b = float64bits(float64(val))
99 expBits = float64ExpBits
100 mantBits = float64MantBits
101 bias = float64Bias
102 }
103
104 neg := b>>(expBits+mantBits) != 0
105 exp := int(b>>mantBits) & (1<<expBits - 1)
106 mant := b & (1<<mantBits - 1)
107 if exp == 1<<expBits-1 {
108 if mant != 0 {
109 return append(dst, "NaN"...)
110 }
111 if neg {
112 return append(dst, "-Inf"...)
113 }
114 return append(dst, "+Inf"...)
115 }
116 if exp == 0 {
117 exp++
118 } else {
119 mant |= 1 << mantBits
120 }
121 exp += bias
122
123
124 if fmt == 'b' {
125 return fmtB(dst, neg, mant, exp-mantBits)
126 }
127 if fmt == 'x' || fmt == 'X' {
128 return fmtX(dst, prec, fmt, neg, mant, exp, mantBits)
129 }
130
131
132 if mant == 0 {
133 return fmtEFG(dst, neg, nil, 0, 0, prec, fmt, prec < 0)
134 }
135
136
137 if prec < 0 {
138
139 var buf [32]byte
140 s := 64 - bits.Len64(mant)
141 m := mant << s
142 e := exp - s
143 d, p := shortFloat[F](m, e-mantBits)
144 dp, nd := setDigits(buf[:], d, p, numDigits(d))
145
146 switch fmt {
147 case 'e', 'E':
148 prec = max(nd-1, 0)
149 case 'f':
150 prec = max(nd-dp, 0)
151 case 'g', 'G':
152 prec = nd
153 }
154 return fmtEFG(dst, neg, buf[:], dp, nd, prec, fmt, true)
155 }
156
157 if optimize {
158
159 digits := prec
160 switch fmt {
161 case 'f':
162
163
164
165 if exp >= 0 {
166 digits = 1 + log10Pow2(1+exp) + prec
167 } else {
168 digits = 1 + prec - log10Pow2(-exp)
169 }
170 case 'e', 'E':
171 digits++
172 case 'g', 'G':
173 if prec == 0 {
174 prec = 1
175 }
176 digits = prec
177 default:
178
179 digits = 1
180 }
181 if digits <= 18 {
182
183
184 var buf [24]byte
185 var dp, nd int
186 if digits > 0 {
187 s := 64 - bits.Len64(mant)
188 m := mant << s
189 e := exp - s
190 d, p := fixedWidthFloat(m, e-mantBits, digits, prec, fmt)
191 if d != 0 {
192 dp, nd = setDigits(buf[:], d, p, numDigits(d))
193 }
194 }
195 return fmtEFG(dst, neg, buf[:], dp, nd, prec, fmt, false)
196 }
197 }
198
199
200 d := new(decimal)
201 d.Assign(mant)
202 d.Shift(exp - mantBits)
203 switch fmt {
204 case 'e', 'E':
205 d.Round(prec + 1)
206 case 'f':
207 d.Round(d.dp + prec)
208 case 'g', 'G':
209 if prec == 0 {
210 prec = 1
211 }
212 d.Round(prec)
213 }
214 return fmtEFG(dst, neg, d.d[:], d.dp, d.nd, prec, fmt, false)
215 }
216
217 func ftoa64(dst []byte, val float64, fmt byte, prec int) []byte {
218 type F = float64
219 var b uint64
220 var expBits, mantBits, bias int
221 switch 8 * unsafe.Sizeof(val) {
222 case 32:
223 b = uint64(float32bits(float32(val)))
224 expBits = float32ExpBits
225 mantBits = float32MantBits
226 bias = float32Bias
227 case 64:
228 b = float64bits(float64(val))
229 expBits = float64ExpBits
230 mantBits = float64MantBits
231 bias = float64Bias
232 }
233
234 neg := b>>(expBits+mantBits) != 0
235 exp := int(b>>mantBits) & (1<<expBits - 1)
236 mant := b & (1<<mantBits - 1)
237 if exp == 1<<expBits-1 {
238 if mant != 0 {
239 return append(dst, "NaN"...)
240 }
241 if neg {
242 return append(dst, "-Inf"...)
243 }
244 return append(dst, "+Inf"...)
245 }
246 if exp == 0 {
247 exp++
248 } else {
249 mant |= 1 << mantBits
250 }
251 exp += bias
252
253
254 if fmt == 'b' {
255 return fmtB(dst, neg, mant, exp-mantBits)
256 }
257 if fmt == 'x' || fmt == 'X' {
258 return fmtX(dst, prec, fmt, neg, mant, exp, mantBits)
259 }
260
261
262 if mant == 0 {
263 return fmtEFG(dst, neg, nil, 0, 0, prec, fmt, prec < 0)
264 }
265
266
267 if prec < 0 {
268
269 var buf [32]byte
270 s := 64 - bits.Len64(mant)
271 m := mant << s
272 e := exp - s
273 d, p := shortFloat[F](m, e-mantBits)
274 dp, nd := setDigits(buf[:], d, p, numDigits(d))
275
276 switch fmt {
277 case 'e', 'E':
278 prec = max(nd-1, 0)
279 case 'f':
280 prec = max(nd-dp, 0)
281 case 'g', 'G':
282 prec = nd
283 }
284 return fmtEFG(dst, neg, buf[:], dp, nd, prec, fmt, true)
285 }
286
287 if optimize {
288
289 digits := prec
290 switch fmt {
291 case 'f':
292
293
294
295 if exp >= 0 {
296 digits = 1 + log10Pow2(1+exp) + prec
297 } else {
298 digits = 1 + prec - log10Pow2(-exp)
299 }
300 case 'e', 'E':
301 digits++
302 case 'g', 'G':
303 if prec == 0 {
304 prec = 1
305 }
306 digits = prec
307 default:
308
309 digits = 1
310 }
311 if digits <= 18 {
312
313
314 var buf [24]byte
315 var dp, nd int
316 if digits > 0 {
317 s := 64 - bits.Len64(mant)
318 m := mant << s
319 e := exp - s
320 d, p := fixedWidthFloat(m, e-mantBits, digits, prec, fmt)
321 if d != 0 {
322 dp, nd = setDigits(buf[:], d, p, numDigits(d))
323 }
324 }
325 return fmtEFG(dst, neg, buf[:], dp, nd, prec, fmt, false)
326 }
327 }
328
329
330 d := new(decimal)
331 d.Assign(mant)
332 d.Shift(exp - mantBits)
333 switch fmt {
334 case 'e', 'E':
335 d.Round(prec + 1)
336 case 'f':
337 d.Round(d.dp + prec)
338 case 'g', 'G':
339 if prec == 0 {
340 prec = 1
341 }
342 d.Round(prec)
343 }
344 return fmtEFG(dst, neg, d.d[:], d.dp, d.nd, prec, fmt, false)
345 }
346
347 func fmtEFG(dst []byte, neg bool, s []byte, dp, nd, prec int, fmt byte, shortest bool) []byte {
348 if fmt == 'g' || fmt == 'G' {
349
350 eprec := prec
351 if eprec > nd && nd >= dp {
352 eprec = nd
353 }
354
355
356
357 if shortest {
358 eprec = 6
359 }
360 exp := dp - 1
361 if exp < -4 || exp >= eprec {
362 if prec > nd {
363 prec = nd
364 }
365 prec--
366 fmt = fmt + 'e' - 'g'
367 } else {
368 if prec > dp {
369 prec = nd
370 }
371 prec = max(prec-dp, 0)
372 fmt = 'f'
373 }
374 }
375
376 switch fmt {
377 case 'e', 'E':
378
379 if neg {
380 dst = append(dst, '-')
381 }
382
383
384 ch := byte('0')
385 if nd != 0 {
386 ch = s[0]
387 }
388 dst = append(dst, ch)
389
390
391 if prec > 0 {
392 dst = append(dst, '.')
393 i := 1
394 m := min(nd, prec+1)
395 if i < m {
396 dst = append(dst, s[i:m]...)
397 i = m
398 }
399 for range prec + 1 - i {
400 dst = append(dst, '0')
401 }
402 }
403
404
405 dst = append(dst, fmt)
406 exp := dp - 1
407 if 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 return dst
428
429 case 'f':
430
431 if neg {
432 dst = append(dst, '-')
433 }
434
435
436 if dp > 0 {
437 m := min(nd, dp)
438 for _, c := range s[:m] {
439 dst = append(dst, c)
440 }
441 for range dp - m {
442 dst = append(dst, '0')
443 }
444 } else {
445 dst = append(dst, '0')
446 }
447
448
449 if prec > 0 {
450 dst = append(dst, '.')
451 lz := min(prec, max(0, -dp))
452 off := dp + lz
453 m := min(prec-lz, max(0, nd-off))
454 tz := max(0, prec-lz-m)
455 for range lz {
456 dst = append(dst, '0')
457 }
458 for i := range m {
459 dst = append(dst, s[off+i])
460 }
461 for range tz {
462 dst = append(dst, '0')
463 }
464 }
465 return dst
466 }
467
468
469 return append(dst, '%', fmt)
470 }
471
472
473 func fmtB(dst []byte, neg bool, mant uint64, exp int) []byte {
474 if neg {
475 dst = append(dst, '-')
476 }
477 dst = AppendUint(dst, mant, 10)
478 dst = append(dst, 'p')
479 if exp >= 0 {
480 dst = append(dst, '+')
481 }
482 dst = AppendInt(dst, int64(exp), 10)
483 return dst
484 }
485
486
487 func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp, mantBits int) []byte {
488 if mant == 0 {
489 exp = 0
490 }
491
492
493
494 mant <<= 60 - 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
View as plain text