1 package ftoa
2
3 import (
4 "math"
5 "math/big"
6 )
7
8 const (
9 exp_11 = 0x3ff00000
10 frac_mask1 = 0xfffff
11 bletch = 0x10
12 quick_max = 14
13 int_max = 14
14 )
15
16 var (
17 tens = [...]float64{
18 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
19 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
20 1e20, 1e21, 1e22,
21 }
22
23 bigtens = [...]float64{1e16, 1e32, 1e64, 1e128, 1e256}
24
25 big5 = big.NewInt(5)
26 big10 = big.NewInt(10)
27
28 p05 = []*big.Int{big5, big.NewInt(25), big.NewInt(125)}
29 pow5Cache [7]*big.Int
30
31 dtoaModes = []int{
32 ModeStandard: 0,
33 ModeStandardExponential: 0,
34 ModeFixed: 3,
35 ModeExponential: 2,
36 ModePrecision: 2,
37 }
38 )
39
40
68 func ftoa(d float64, mode int, biasUp bool, ndigits int, buf []byte) ([]byte, int) {
69 startPos := len(buf)
70 dblBits := make([]byte, 0, 8)
71 be, bbits, dblBits := d2b(d, dblBits)
72
73 dBits := math.Float64bits(d)
74 word0 := uint32(dBits >> 32)
75 word1 := uint32(dBits)
76
77 i := int((word0 >> exp_shift1) & (exp_mask >> exp_shift1))
78 var d2 float64
79 var denorm bool
80 if i != 0 {
81 d2 = setWord0(d, (word0&frac_mask1)|exp_11)
82 i -= bias
83 denorm = false
84 } else {
85
86 i = bbits + be + (bias + (p - 1) - 1)
87 var x uint64
88 if i > 32 {
89 x = uint64(word0)<<(64-i) | uint64(word1)>>(i-32)
90 } else {
91 x = uint64(word1) << (32 - i)
92 }
93 d2 = setWord0(float64(x), uint32((x>>32)-31*exp_mask))
94 i -= (bias + (p - 1) - 1) + 1
95 denorm = true
96 }
97
98 ds := (d2-1.5)*0.289529654602168 + 0.1760912590558 + float64(i)*0.301029995663981
99 k := int(ds)
100 if ds < 0.0 && ds != float64(k) {
101 k--
102 }
103 k_check := true
104 if k >= 0 && k < len(tens) {
105 if d < tens[k] {
106 k--
107 }
108 k_check = false
109 }
110
112 j := bbits - i - 1
113 var b2, s2, b5, s5 int
114
115 if j >= 0 {
116 b2 = 0
117 s2 = j
118 } else {
119 b2 = -j
120 s2 = 0
121 }
122 if k >= 0 {
123 b5 = 0
124 s5 = k
125 s2 += k
126 } else {
127 b2 -= k
128 b5 = -k
129 s5 = 0
130 }
131
133 if mode < 0 || mode > 9 {
134 mode = 0
135 }
136 try_quick := true
137 if mode > 5 {
138 mode -= 4
139 try_quick = false
140 }
141 leftright := true
142 var ilim, ilim1 int
143 switch mode {
144 case 0, 1:
145 ilim, ilim1 = -1, -1
146 ndigits = 0
147 case 2:
148 leftright = false
149 fallthrough
150 case 4:
151 if ndigits <= 0 {
152 ndigits = 1
153 }
154 ilim, ilim1 = ndigits, ndigits
155 case 3:
156 leftright = false
157 fallthrough
158 case 5:
159 i = ndigits + k + 1
160 ilim = i
161 ilim1 = i - 1
162 }
163
164
166 fast_failed := false
167 if ilim >= 0 && ilim <= quick_max && try_quick {
168
169
170
171 i = 0
172 d2 = d
173 k0 := k
174 ilim0 := ilim
175 ieps := 2
176
177 if k > 0 {
178 ds = tens[k&0xf]
179 j = k >> 4
180 if (j & bletch) != 0 {
181
182 j &= bletch - 1
183 d /= bigtens[len(bigtens)-1]
184 ieps++
185 }
186 for ; j != 0; i++ {
187 if (j & 1) != 0 {
188 ieps++
189 ds *= bigtens[i]
190 }
191 j >>= 1
192 }
193 d /= ds
194 } else if j1 := -k; j1 != 0 {
195 d *= tens[j1&0xf]
196 for j = j1 >> 4; j != 0; i++ {
197 if (j & 1) != 0 {
198 ieps++
199 d *= bigtens[i]
200 }
201 j >>= 1
202 }
203 }
204
205 if k_check && d < 1.0 && ilim > 0 {
206 if ilim1 <= 0 {
207 fast_failed = true
208 } else {
209 ilim = ilim1
210 k--
211 d *= 10.
212 ieps++
213 }
214 }
215
216 eps := float64(ieps)*d + 7.0
217 eps = setWord0(eps, _word0(eps)-(p-1)*exp_msk1)
218 if ilim == 0 {
219 d -= 5.0
220 if d > eps {
221 buf = append(buf, '1')
222 k++
223 return buf, k + 1
224 }
225 if d < -eps {
226 buf = append(buf, '0')
227 return buf, 1
228 }
229 fast_failed = true
230 }
231 if !fast_failed {
232 fast_failed = true
233 if leftright {
234
237 eps = 0.5/tens[ilim-1] - eps
238 for i = 0; ; {
239 l := int64(d)
240 d -= float64(l)
241 buf = append(buf, byte('0'+l))
242 if d < eps {
243 return buf, k + 1
244 }
245 if 1.0-d < eps {
246 buf, k = bumpUp(buf, k)
247 return buf, k + 1
248 }
249 i++
250 if i >= ilim {
251 break
252 }
253 eps *= 10.0
254 d *= 10.0
255 }
256 } else {
257
258 eps *= tens[ilim-1]
259 for i = 1; ; i++ {
260 l := int64(d)
261 d -= float64(l)
262 buf = append(buf, byte('0'+l))
263 if i == ilim {
264 if d > 0.5+eps {
265 buf, k = bumpUp(buf, k)
266 return buf, k + 1
267 } else if d < 0.5-eps {
268 buf = stripTrailingZeroes(buf, startPos)
269 return buf, k + 1
270 }
271 break
272 }
273 d *= 10.0
274 }
275 }
276 }
277 if fast_failed {
278 buf = buf[:startPos]
279 d = d2
280 k = k0
281 ilim = ilim0
282 }
283 }
284
285
286 if be >= 0 && k <= int_max {
287
288 ds = tens[k]
289 if ndigits < 0 && ilim <= 0 {
290 if ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds) {
291 buf = buf[:startPos]
292 buf = append(buf, '0')
293 return buf, 1
294 }
295 buf = append(buf, '1')
296 k++
297 return buf, k + 1
298 }
299 for i = 1; ; i++ {
300 l := int64(d / ds)
301 d -= float64(l) * ds
302 buf = append(buf, byte('0'+l))
303 if i == ilim {
304 d += d
305 if (d > ds) || (d == ds && (((l & 1) != 0) || biasUp)) {
306 buf, k = bumpUp(buf, k)
307 }
308 break
309 }
310 d *= 10.0
311 if d == 0 {
312 break
313 }
314 }
315 return buf, k + 1
316 }
317
318 m2 := b2
319 m5 := b5
320 var mhi, mlo *big.Int
321 if leftright {
322 if mode < 2 {
323 if denorm {
324 i = be + (bias + (p - 1) - 1 + 1)
325 } else {
326 i = 1 + p - bbits
327 }
328
330 } else {
331 j = ilim - 1
332 if m5 >= j {
333 m5 -= j
334 } else {
335 j -= m5
336 s5 += j
337 b5 += j
338 m5 = 0
339 }
340 i = ilim
341 if i < 0 {
342 m2 -= i
343 i = 0
344 }
345
346 }
347 b2 += i
348 s2 += i
349 mhi = big.NewInt(1)
350
352 }
353
354
356 if m2 > 0 && s2 > 0 {
357 if m2 < s2 {
358 i = m2
359 } else {
360 i = s2
361 }
362 b2 -= i
363 m2 -= i
364 s2 -= i
365 }
366
367 b := new(big.Int).SetBytes(dblBits)
368
369 if b5 > 0 {
370 if leftright {
371 if m5 > 0 {
372 pow5mult(mhi, m5)
373 b.Mul(mhi, b)
374 }
375 j = b5 - m5
376 if j != 0 {
377 pow5mult(b, j)
378 }
379 } else {
380 pow5mult(b, b5)
381 }
382 }
383
385
386 S := big.NewInt(1)
387 if s5 > 0 {
388 pow5mult(S, s5)
389 }
390
392
393
394 spec_case := false
395 if mode < 2 {
396 if (_word1(d) == 0) && ((_word0(d) & bndry_mask) == 0) &&
397 ((_word0(d) & (exp_mask & (exp_mask << 1))) != 0) {
398
400 b2 += log2P
401 s2 += log2P
402 spec_case = true
403 }
404 }
405
406
413 var zz int
414 if s5 != 0 {
415 S_bytes := S.Bytes()
416 var S_hiWord uint32
417 for idx := 0; idx < 4; idx++ {
418 S_hiWord = S_hiWord << 8
419 if idx < len(S_bytes) {
420 S_hiWord |= uint32(S_bytes[idx])
421 }
422 }
423 zz = 32 - hi0bits(S_hiWord)
424 } else {
425 zz = 1
426 }
427 i = (zz + s2) & 0x1f
428 if i != 0 {
429 i = 32 - i
430 }
431
432 if i > 4 {
433 i -= 4
434 b2 += i
435 m2 += i
436 s2 += i
437 } else if i < 4 {
438 i += 28
439 b2 += i
440 m2 += i
441 s2 += i
442 }
443
444 if b2 > 0 {
445 b = b.Lsh(b, uint(b2))
446 }
447 if s2 > 0 {
448 S.Lsh(S, uint(s2))
449 }
450
452 if k_check {
453 if b.Cmp(S) < 0 {
454 k--
455 b.Mul(b, big10)
456 if leftright {
457 mhi.Mul(mhi, big10)
458 }
459 ilim = ilim1
460 }
461 }
462
463
464 if ilim <= 0 && mode > 2 {
465
467 if ilim >= 0 {
468 i = b.Cmp(S.Mul(S, big5))
469 }
470 if ilim < 0 || i < 0 || i == 0 && !biasUp {
471
473 buf = buf[:startPos]
474 buf = append(buf, '0')
475 return buf, 1
476 }
477 buf = append(buf, '1')
478 k++
479 return buf, k + 1
480 }
481
482 var dig byte
483 if leftright {
484 if m2 > 0 {
485 mhi.Lsh(mhi, uint(m2))
486 }
487
488
491
492 mlo = mhi
493 if spec_case {
494 mhi = mlo
495 mhi = new(big.Int).Lsh(mhi, log2P)
496 }
497
498
499 var z, delta big.Int
500 for i = 1; ; i++ {
501 z.DivMod(b, S, b)
502 dig = byte(z.Int64() + '0')
503
506 j = b.Cmp(mlo)
507
508 delta.Sub(S, mhi)
509 var j1 int
510 if delta.Sign() <= 0 {
511 j1 = 1
512 } else {
513 j1 = b.Cmp(&delta)
514 }
515
516 if (j1 == 0) && (mode == 0) && ((_word1(d) & 1) == 0) {
517 if dig == '9' {
518 var flag bool
519 buf = append(buf, '9')
520 if buf, flag = roundOff(buf, startPos); flag {
521 k++
522 buf = append(buf, '1')
523 }
524 return buf, k + 1
525 }
526 if j > 0 {
527 dig++
528 }
529 buf = append(buf, dig)
530 return buf, k + 1
531 }
532 if (j < 0) || ((j == 0) && (mode == 0) && ((_word1(d) & 1) == 0)) {
533 if j1 > 0 {
534
536 b.Lsh(b, 1)
537 j1 = b.Cmp(S)
538 if (j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp)) {
539 dig++
540 if dig == '9' {
541 buf = append(buf, '9')
542 buf, flag := roundOff(buf, startPos)
543 if flag {
544 k++
545 buf = append(buf, '1')
546 }
547 return buf, k + 1
548 }
549 }
550 }
551 buf = append(buf, dig)
552 return buf, k + 1
553 }
554 if j1 > 0 {
555 if dig == '9' {
556 buf = append(buf, '9')
557 buf, flag := roundOff(buf, startPos)
558 if flag {
559 k++
560 buf = append(buf, '1')
561 }
562 return buf, k + 1
563 }
564 buf = append(buf, dig+1)
565 return buf, k + 1
566 }
567 buf = append(buf, dig)
568 if i == ilim {
569 break
570 }
571 b.Mul(b, big10)
572 if mlo == mhi {
573 mhi.Mul(mhi, big10)
574 } else {
575 mlo.Mul(mlo, big10)
576 mhi.Mul(mhi, big10)
577 }
578 }
579 } else {
580 var z big.Int
581 for i = 1; ; i++ {
582 z.DivMod(b, S, b)
583 dig = byte(z.Int64() + '0')
584 buf = append(buf, dig)
585 if i >= ilim {
586 break
587 }
588
589 b.Mul(b, big10)
590 }
591 }
592
593
594 b.Lsh(b, 1)
595 j = b.Cmp(S)
596 if (j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp)) {
597 var flag bool
598 buf, flag = roundOff(buf, startPos)
599 if flag {
600 k++
601 buf = append(buf, '1')
602 return buf, k + 1
603 }
604 } else {
605 buf = stripTrailingZeroes(buf, startPos)
606 }
607
608 return buf, k + 1
609 }
610
611 func bumpUp(buf []byte, k int) ([]byte, int) {
612 var lastCh byte
613 stop := 0
614 if len(buf) > 0 && buf[0] == '-' {
615 stop = 1
616 }
617 for {
618 lastCh = buf[len(buf)-1]
619 buf = buf[:len(buf)-1]
620 if lastCh != '9' {
621 break
622 }
623 if len(buf) == stop {
624 k++
625 lastCh = '0'
626 break
627 }
628 }
629 buf = append(buf, lastCh+1)
630 return buf, k
631 }
632
633 func setWord0(d float64, w uint32) float64 {
634 dBits := math.Float64bits(d)
635 return math.Float64frombits(uint64(w)<<32 | dBits&0xffffffff)
636 }
637
638 func _word0(d float64) uint32 {
639 dBits := math.Float64bits(d)
640 return uint32(dBits >> 32)
641 }
642
643 func _word1(d float64) uint32 {
644 dBits := math.Float64bits(d)
645 return uint32(dBits)
646 }
647
648 func stripTrailingZeroes(buf []byte, startPos int) []byte {
649 bl := len(buf) - 1
650 for bl >= startPos && buf[bl] == '0' {
651 bl--
652 }
653 return buf[:bl+1]
654 }
655
656
657 func pow5mult(b *big.Int, k int) *big.Int {
658 if k < (1 << (len(pow5Cache) + 2)) {
659 i := k & 3
660 if i != 0 {
661 b.Mul(b, p05[i-1])
662 }
663 k >>= 2
664 i = 0
665 for {
666 if k&1 != 0 {
667 b.Mul(b, pow5Cache[i])
668 }
669 k >>= 1
670 if k == 0 {
671 break
672 }
673 i++
674 }
675 return b
676 }
677 return b.Mul(b, new(big.Int).Exp(big5, big.NewInt(int64(k)), nil))
678 }
679
680 func roundOff(buf []byte, startPos int) ([]byte, bool) {
681 i := len(buf)
682 for i != startPos {
683 i--
684 if buf[i] != '9' {
685 buf[i]++
686 return buf[:i+1], false
687 }
688 }
689 return buf[:startPos], true
690 }
691
692 func init() {
693 p := big.NewInt(625)
694 pow5Cache[0] = p
695 for i := 1; i < len(pow5Cache); i++ {
696 p = new(big.Int).Mul(p, p)
697 pow5Cache[i] = p
698 }
699 }
700
View as plain text