1
2
3
4
5
6
7
8
9 package strconv
10
11 import (
12 "math/bits"
13 "unsafe"
14 )
15
16
17 func bool2[T ~int | ~uint32 | ~uint64](b bool) T {
18 if b {
19 return 1
20 }
21 return 0
22 }
23
24
25
26
27 func pack64(m uint64, e int) (float64, error) {
28 if m&(1<<52) == 0 {
29 return float64frombits(m), nil
30 }
31 if e >= 0x7FF-1075 {
32 return float64frombits(m&(1<<63) | 0x7ff<<52), ErrRange
33 }
34 return float64frombits(m&^(1<<52) | uint64(1075+e)<<52), nil
35 }
36
37
38
39
40 func pack32(m uint32, e int) (float32, error) {
41 if m&(1<<23) == 0 {
42 return float32frombits(m), nil
43 }
44 if e >= 0xFF-150 {
45 return float32frombits(m&(1<<31) | 0xff<<23), ErrRange
46 }
47 return float32frombits(m&^(1<<23) | uint32(150+e)<<23), nil
48 }
49
50
51 type unrounded uint64
52
53 func (u unrounded) floor() uint64 { return uint64((u + 0) >> 2) }
54 func (u unrounded) roundHalfDown() uint64 { return uint64((u + 1) >> 2) }
55 func (u unrounded) round() uint64 { return uint64((u + 1 + (u>>2)&1) >> 2) }
56 func (u unrounded) roundHalfUp() uint64 { return uint64((u + 2) >> 2) }
57 func (u unrounded) ceil() uint64 { return uint64((u + 3) >> 2) }
58 func (u unrounded) nudge(δ int) unrounded { return u + unrounded(δ) }
59
60 func (u unrounded) div(d uint64) unrounded {
61 x := uint64(u)
62 return unrounded(x/d) | u&1 | bool2[unrounded](x%d != 0)
63 }
64
65 func (u unrounded) rsh(s int) unrounded {
66 return u>>s | u&1 | bool2[unrounded](u&((1<<s)-1) != 0)
67 }
68
69
70 func log10Pow2(x int) int {
71
72 return (x * 78913) >> 18
73 }
74
75
76 func log2Pow10(x int) int {
77
78 return (x * 108853) >> 15
79 }
80
81
82 var uint64pow10 = [...]uint64{
83 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
84 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
85 }
86
87
88
89
90
91 func fixedWidthFloat(m uint64, e, n, prec int, fmt byte) (d uint64, p int) {
92 p = n - 1 - log10Pow2(e+63)
93 var pre scaler
94 prescale(&pre, e, p, log2Pow10(p))
95 u := uscale(m, &pre)
96 if u >= unmin(uint64pow10[n]) {
97 u = u.div(10)
98 p--
99 }
100 if fmt == 'f' {
101 for p > prec {
102 u = u.div(10)
103 p--
104 }
105 }
106 return u.round(), -p
107 }
108
109
110
111
112 func parseFloat64(d uint64, p int, sign uint64) (float64, error) {
113 b := bits.Len64(d)
114 lp := log2Pow10(p)
115 e := min(1074, 53-b-lp)
116 var pre scaler
117 prescale(&pre, e-(64-b), p, lp)
118 if pre.s >= 64 {
119 return float64frombits(sign | 0), nil
120 }
121 u := uscale(d<<(64-b), &pre)
122
123
124
125
126
127
128 s := bool2[int](u >= unmin(1<<53))
129 u = u>>s | u&1
130 e = e - s
131
132 return pack64(sign|u.round(), -e)
133 }
134
135
136
137
138 func parseFloat32(d uint64, p int, sign uint32) (float32, error) {
139 b := bits.Len64(d)
140 lp := log2Pow10(p)
141 e := min(149, 24-b-lp)
142 var pre scaler
143 prescale(&pre, e-(64-b), p, lp)
144 if pre.s >= 64 {
145 return float32frombits(sign | 0), nil
146 }
147 u := uscale(d<<(64-b), &pre)
148
149
150
151
152
153
154 s := bool2[int](u >= unmin(1<<24))
155 u = u>>s | u&1
156 e = e - s
157
158 return pack32(sign|uint32(u.round()), -e)
159 }
160
161
162 func unmin(x uint64) unrounded {
163 return unrounded(x<<2 - 2)
164 }
165
166
167
168
169 func shortFloat[F float32 | float64](m uint64, e int) (d uint64, p int) {
170 var mantBits, minExp int
171 switch 8 * unsafe.Sizeof(F(0)) {
172 case 32:
173 mantBits = float32MantBits
174 minExp = float32MinExp
175 case 64:
176 mantBits = float64MantBits
177 minExp = float64MinExp
178 }
179
180
181
182
183 var min, max uint64
184 var odd int
185 z := 63 - mantBits
186 if m == 1<<63 && e > minExp {
187 p = -skewed(e + z)
188 min = m - 1<<(z-2)
189 max = m + 1<<(z-1)
190 odd = int(m>>z) & 1
191 } else if e >= minExp {
192 p = -log10Pow2(e + z)
193 min = m - 1<<(z-1)
194 max = m + 1<<(z-1)
195 odd = int(m>>z) & 1
196 } else {
197 z = z + (minExp - e)
198 p = -log10Pow2(e + z)
199 min = m - 1<<(z-1)
200 max = m + 1<<(z-1)
201 odd = int(m>>z) & 1
202 }
203
204 var pre scaler
205 prescale(&pre, e, p, log2Pow10(p))
206 dmin := uscale(min, &pre).nudge(+odd).ceil()
207 dmax := uscale(max, &pre).nudge(-odd).floor()
208
209 if d = dmax / 10; d*10 >= dmin {
210 return d, -(p - 1)
211 }
212 if d = dmin; d < dmax {
213 d = uscale(m, &pre).round()
214 }
215 return d, -p
216 }
217
218
219
220 func skewed(e int) int {
221 return (e*631305 - 261663) >> 21
222 }
223
224
225 type pmHiLo struct {
226 hi uint64
227 lo uint64
228 }
229
230
231 type scaler struct {
232
233 pmHi uint64
234 pmLo uint64
235 s int
236 }
237
238
239
240
241
242
243
244
245
246 func prescale(pre *scaler, e, p, lp int) {
247 pre.pmHi = pow10Tab[p-pow10Min].hi
248 pre.pmLo = pow10Tab[p-pow10Min].lo
249 pre.s = -(e + lp + 3)
250 }
251
252
253
254
255
256
257
258 func uscale(x uint64, c *scaler) unrounded {
259 hi, mid := bits.Mul64(x, c.pmHi)
260 s := c.s & 63
261 if hi>>s<<s != hi {
262 return unrounded(hi>>s | 1)
263 }
264 mid2, _ := bits.Mul64(x, c.pmLo)
265 hi -= bool2[uint64](mid < mid2)
266 return unrounded(hi>>s | bool2[uint64](mid-mid2 > 1))
267 }
268
269
270 func setDigits(s []byte, d uint64, p, nd int) (dp, nzd int) {
271
272
273
274
275 if nd <= len(s) {
276 formatBase10(s[:nd], d)
277 dp = nd + p
278 for nd > 0 && s[nd-1] == '0' {
279 nd--
280 }
281 }
282 return dp, nd
283 }
284
285
286
287 func numDigits(d uint64) int {
288 nd := log10Pow2(bits.Len64(d))
289 return nd + bool2[int](d >= uint64pow10[nd])
290 }
291
View as plain text