Source file
src/math/big/ftoa.go
1
2
3
4
5
6
7
8
9 package big
10
11 import (
12 "bytes"
13 "fmt"
14 "strconv"
15 )
16
17
18
19
20
21
22
23
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 (x *Float) Text(format byte, prec int) string {
48 cap := 10
49 if prec > 0 {
50 cap += prec
51 }
52 return string(x.Append(make([]byte, 0, cap), format, prec))
53 }
54
55
56
57 func (x *Float) String() string {
58 return x.Text('g', 10)
59 }
60
61
62
63 func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
64
65 if x.neg {
66 buf = append(buf, '-')
67 }
68
69
70 if x.form == inf {
71 if !x.neg {
72 buf = append(buf, '+')
73 }
74 return append(buf, "Inf"...)
75 }
76
77
78 switch fmt {
79 case 'b':
80 return x.fmtB(buf)
81 case 'p':
82 return x.fmtP(buf)
83 case 'x':
84 return x.fmtX(buf, prec)
85 }
86
87
88
89
90
91
92
93 var d decimal
94 if x.form == finite {
95
96 d.init(x.mant, int(x.exp)-x.mant.bitLen())
97 }
98
99
100 shortest := false
101 if prec < 0 {
102 shortest = true
103 roundShortest(&d, x)
104
105 switch fmt {
106 case 'e', 'E':
107 prec = len(d.mant) - 1
108 case 'f':
109 prec = max(len(d.mant)-d.exp, 0)
110 case 'g', 'G':
111 prec = len(d.mant)
112 }
113 } else {
114
115 switch fmt {
116 case 'e', 'E':
117
118 d.round(1 + prec)
119 case 'f':
120
121 d.round(d.exp + prec)
122 case 'g', 'G':
123 if prec == 0 {
124 prec = 1
125 }
126 d.round(prec)
127 }
128 }
129
130
131 switch fmt {
132 case 'e', 'E':
133 return fmtE(buf, fmt, prec, d)
134 case 'f':
135 return fmtF(buf, prec, d)
136 case 'g', 'G':
137
138 eprec := prec
139 if eprec > len(d.mant) && len(d.mant) >= d.exp {
140 eprec = len(d.mant)
141 }
142
143
144
145
146 if shortest {
147 eprec = 6
148 }
149 exp := d.exp - 1
150 if exp < -4 || exp >= eprec {
151 if prec > len(d.mant) {
152 prec = len(d.mant)
153 }
154 return fmtE(buf, fmt+'e'-'g', prec-1, d)
155 }
156 if prec > d.exp {
157 prec = len(d.mant)
158 }
159 return fmtF(buf, max(prec-d.exp, 0), d)
160 }
161
162
163 if x.neg {
164 buf = buf[:len(buf)-1]
165 }
166 return append(buf, '%', fmt)
167 }
168
169 func roundShortest(d *decimal, x *Float) {
170
171 if len(d.mant) == 0 {
172 return
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186 mant := nat(nil).set(x.mant)
187 exp := int(x.exp) - mant.bitLen()
188 s := mant.bitLen() - int(x.prec+1)
189 switch {
190 case s < 0:
191 mant = mant.shl(mant, uint(-s))
192 case s > 0:
193 mant = mant.shr(mant, uint(+s))
194 }
195 exp += s
196
197
198
199 var lower decimal
200 var tmp nat
201 lower.init(tmp.sub(mant, natOne), exp)
202
203
204 var upper decimal
205 upper.init(tmp.add(mant, natOne), exp)
206
207
208
209
210 inclusive := mant[0]&2 == 0
211
212
213
214 for i, m := range d.mant {
215 l := lower.at(i)
216 u := upper.at(i)
217
218
219
220
221 okdown := l != m || inclusive && i+1 == len(lower.mant)
222
223
224
225 okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant))
226
227
228
229 switch {
230 case okdown && okup:
231 d.round(i + 1)
232 return
233 case okdown:
234 d.roundDown(i + 1)
235 return
236 case okup:
237 d.roundUp(i + 1)
238 return
239 }
240 }
241 }
242
243
244 func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
245
246 ch := byte('0')
247 if len(d.mant) > 0 {
248 ch = d.mant[0]
249 }
250 buf = append(buf, ch)
251
252
253 if prec > 0 {
254 buf = append(buf, '.')
255 i := 1
256 m := min(len(d.mant), prec+1)
257 if i < m {
258 buf = append(buf, d.mant[i:m]...)
259 i = m
260 }
261 for ; i <= prec; i++ {
262 buf = append(buf, '0')
263 }
264 }
265
266
267 buf = append(buf, fmt)
268 var exp int64
269 if len(d.mant) > 0 {
270 exp = int64(d.exp) - 1
271 }
272 if exp < 0 {
273 ch = '-'
274 exp = -exp
275 } else {
276 ch = '+'
277 }
278 buf = append(buf, ch)
279
280
281 if exp < 10 {
282 buf = append(buf, '0')
283 }
284 return strconv.AppendInt(buf, exp, 10)
285 }
286
287
288 func fmtF(buf []byte, prec int, d decimal) []byte {
289
290 if d.exp > 0 {
291 m := min(len(d.mant), d.exp)
292 buf = append(buf, d.mant[:m]...)
293 for ; m < d.exp; m++ {
294 buf = append(buf, '0')
295 }
296 } else {
297 buf = append(buf, '0')
298 }
299
300
301 if prec > 0 {
302 buf = append(buf, '.')
303 for i := 0; i < prec; i++ {
304 buf = append(buf, d.at(d.exp+i))
305 }
306 }
307
308 return buf
309 }
310
311
312
313
314
315
316
317
318 func (x *Float) fmtB(buf []byte) []byte {
319 if x.form == zero {
320 return append(buf, '0')
321 }
322
323 if debugFloat && x.form != finite {
324 panic("non-finite float")
325 }
326
327
328
329 m := x.mant
330 switch w := uint32(len(x.mant)) * _W; {
331 case w < x.prec:
332 m = nat(nil).shl(m, uint(x.prec-w))
333 case w > x.prec:
334 m = nat(nil).shr(m, uint(w-x.prec))
335 }
336
337 buf = append(buf, m.utoa(10)...)
338 buf = append(buf, 'p')
339 e := int64(x.exp) - int64(x.prec)
340 if e >= 0 {
341 buf = append(buf, '+')
342 }
343 return strconv.AppendInt(buf, e, 10)
344 }
345
346
347
348
349
350
351
352 func (x *Float) fmtX(buf []byte, prec int) []byte {
353 if x.form == zero {
354 buf = append(buf, "0x0"...)
355 if prec > 0 {
356 buf = append(buf, '.')
357 for i := 0; i < prec; i++ {
358 buf = append(buf, '0')
359 }
360 }
361 buf = append(buf, "p+00"...)
362 return buf
363 }
364
365 if debugFloat && x.form != finite {
366 panic("non-finite float")
367 }
368
369
370 var n uint
371 if prec < 0 {
372 n = 1 + (x.MinPrec()-1+3)/4*4
373 } else {
374 n = 1 + 4*uint(prec)
375 }
376
377 x = new(Float).SetPrec(n).SetMode(x.mode).Set(x)
378
379
380 m := x.mant
381 switch w := uint(len(x.mant)) * _W; {
382 case w < n:
383 m = nat(nil).shl(m, n-w)
384 case w > n:
385 m = nat(nil).shr(m, w-n)
386 }
387 exp64 := int64(x.exp) - 1
388
389 hm := m.utoa(16)
390 if debugFloat && hm[0] != '1' {
391 panic("incorrect mantissa: " + string(hm))
392 }
393 buf = append(buf, "0x1"...)
394 if len(hm) > 1 {
395 buf = append(buf, '.')
396 buf = append(buf, hm[1:]...)
397 }
398
399 buf = append(buf, 'p')
400 if exp64 >= 0 {
401 buf = append(buf, '+')
402 } else {
403 exp64 = -exp64
404 buf = append(buf, '-')
405 }
406
407 if exp64 < 10 {
408 buf = append(buf, '0')
409 }
410 return strconv.AppendInt(buf, exp64, 10)
411 }
412
413
414
415
416
417
418
419 func (x *Float) fmtP(buf []byte) []byte {
420 if x.form == zero {
421 return append(buf, '0')
422 }
423
424 if debugFloat && x.form != finite {
425 panic("non-finite float")
426 }
427
428
429
430
431 m := x.mant
432 i := 0
433 for i < len(m) && m[i] == 0 {
434 i++
435 }
436 m = m[i:]
437
438 buf = append(buf, "0x."...)
439 buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...)
440 buf = append(buf, 'p')
441 if x.exp >= 0 {
442 buf = append(buf, '+')
443 }
444 return strconv.AppendInt(buf, int64(x.exp), 10)
445 }
446
447 func min(x, y int) int {
448 if x < y {
449 return x
450 }
451 return y
452 }
453
454 var _ fmt.Formatter = &floatZero
455
456
457
458
459
460
461
462
463
464
465 func (x *Float) Format(s fmt.State, format rune) {
466 prec, hasPrec := s.Precision()
467 if !hasPrec {
468 prec = 6
469 }
470
471 switch format {
472 case 'e', 'E', 'f', 'b', 'p', 'x':
473
474 case 'F':
475
476 format = 'f'
477 case 'v':
478
479 format = 'g'
480 fallthrough
481 case 'g', 'G':
482 if !hasPrec {
483 prec = -1
484 }
485 default:
486 fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
487 return
488 }
489 var buf []byte
490 buf = x.Append(buf, byte(format), prec)
491 if len(buf) == 0 {
492 buf = []byte("?")
493 }
494
495
496 var sign string
497 switch {
498 case buf[0] == '-':
499 sign = "-"
500 buf = buf[1:]
501 case buf[0] == '+':
502
503 sign = "+"
504 if s.Flag(' ') {
505 sign = " "
506 }
507 buf = buf[1:]
508 case s.Flag('+'):
509 sign = "+"
510 case s.Flag(' '):
511 sign = " "
512 }
513
514 var padding int
515 if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) {
516 padding = width - len(sign) - len(buf)
517 }
518
519 switch {
520 case s.Flag('0') && !x.IsInf():
521
522 writeMultiple(s, sign, 1)
523 writeMultiple(s, "0", padding)
524 s.Write(buf)
525 case s.Flag('-'):
526
527 writeMultiple(s, sign, 1)
528 s.Write(buf)
529 writeMultiple(s, " ", padding)
530 default:
531
532 writeMultiple(s, " ", padding)
533 writeMultiple(s, sign, 1)
534 s.Write(buf)
535 }
536 }
537
View as plain text