...
1 package ftoa
2
3 import (
4 "fmt"
5 "math"
6 "math/big"
7 "strconv"
8 "strings"
9 )
10
11 const (
12 digits = "0123456789abcdefghijklmnopqrstuvwxyz"
13 )
14
15 func FToBaseStr(num float64, radix int) string {
16 var negative bool
17 if num < 0 {
18 num = -num
19 negative = true
20 }
21
22 dfloor := math.Floor(num)
23 ldfloor := int64(dfloor)
24 var intDigits string
25 if dfloor == float64(ldfloor) {
26 if negative {
27 ldfloor = -ldfloor
28 }
29 intDigits = strconv.FormatInt(ldfloor, radix)
30 } else {
31 floorBits := math.Float64bits(num)
32 exp := int(floorBits>>exp_shiftL) & exp_mask_shifted
33 var mantissa int64
34 if exp == 0 {
35 mantissa = int64((floorBits & frac_maskL) << 1)
36 } else {
37 mantissa = int64((floorBits & frac_maskL) | exp_msk1L)
38 }
39
40 if negative {
41 mantissa = -mantissa
42 }
43 exp -= 1075
44 x := big.NewInt(mantissa)
45 if exp > 0 {
46 x.Lsh(x, uint(exp))
47 } else if exp < 0 {
48 x.Rsh(x, uint(-exp))
49 }
50 intDigits = x.Text(radix)
51 }
52
53 if num == dfloor {
54
55 return intDigits
56 } else {
57
58 var buffer strings.Builder
59 buffer.WriteString(intDigits)
60 buffer.WriteByte('.')
61 df := num - dfloor
62
63 dBits := math.Float64bits(num)
64 word0 := uint32(dBits >> 32)
65 word1 := uint32(dBits)
66
67 dblBits := make([]byte, 0, 8)
68 e, _, dblBits := d2b(df, dblBits)
69
70
71
72 s2 := -int((word0 >> exp_shift1) & (exp_mask >> exp_shift1))
73 if s2 == 0 {
74 s2 = -1
75 }
76 s2 += bias + p
77
78
79 if -s2 >= e {
80 panic(fmt.Errorf("-s2 >= e: %d, %d", -s2, e))
81 }
82 mlo := big.NewInt(1)
83 mhi := mlo
84 if (word1 == 0) && ((word0 & bndry_mask) == 0) && ((word0 & (exp_mask & (exp_mask << 1))) != 0) {
85
87 s2 += log2P
88 mhi = big.NewInt(1 << log2P)
89 }
90
91 b := new(big.Int).SetBytes(dblBits)
92 b.Lsh(b, uint(e+s2))
93 s := big.NewInt(1)
94 s.Lsh(s, uint(s2))
95
100 bigBase := big.NewInt(int64(radix))
101
102 done := false
103 m := &big.Int{}
104 delta := &big.Int{}
105 for !done {
106 b.Mul(b, bigBase)
107 b.DivMod(b, s, m)
108 digit := byte(b.Int64())
109 b, m = m, b
110 mlo.Mul(mlo, bigBase)
111 if mlo != mhi {
112 mhi.Mul(mhi, bigBase)
113 }
114
115
116 j := b.Cmp(mlo)
117
118
119 delta.Sub(s, mhi)
120 var j1 int
121 if delta.Sign() <= 0 {
122 j1 = 1
123 } else {
124 j1 = b.Cmp(delta)
125 }
126
127 if j1 == 0 && (word1&1) == 0 {
128 if j > 0 {
129 digit++
130 }
131 done = true
132 } else if j < 0 || (j == 0 && ((word1 & 1) == 0)) {
133 if j1 > 0 {
134
136 b.Lsh(b, 1)
137 j1 = b.Cmp(s)
138 if j1 > 0 {
139 digit++
140 }
141 }
142 done = true
143 } else if j1 > 0 {
144 digit++
145 done = true
146 }
147
148 buffer.WriteByte(digits[digit])
149 }
150
151 return buffer.String()
152 }
153 }
154
View as plain text