Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Tiny float64 printing and parsing library |
3 | | * |
4 | | * Copyright (c) 2024 Fabrice Bellard |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to deal |
8 | | * in the Software without restriction, including without limitation the rights |
9 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | | * copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice shall be included in |
14 | | * all copies or substantial portions of the Software. |
15 | | * |
16 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | | * THE SOFTWARE. |
23 | | */ |
24 | | #include <stdlib.h> |
25 | | #include <stdio.h> |
26 | | #include <stdarg.h> |
27 | | #include <inttypes.h> |
28 | | #include <string.h> |
29 | | #include <assert.h> |
30 | | #include <ctype.h> |
31 | | #include <sys/time.h> |
32 | | #include <math.h> |
33 | | #include <setjmp.h> |
34 | | |
35 | | #include "cutils.h" |
36 | | #include "dtoa.h" |
37 | | |
38 | | /* |
39 | | TODO: |
40 | | - test n_digits=101 instead of 100 |
41 | | - simplify subnormal handling |
42 | | - reduce max memory usage |
43 | | - free format: could add shortcut if exact result |
44 | | - use 64 bit limb_t when possible |
45 | | - use another algorithm for free format dtoa in base 10 (ryu ?) |
46 | | */ |
47 | | |
48 | | #define USE_POW5_TABLE |
49 | | /* use fast path to print small integers in free format */ |
50 | | #define USE_FAST_INT |
51 | | |
52 | 0 | #define LIMB_LOG2_BITS 5 |
53 | | |
54 | 0 | #define LIMB_BITS (1 << LIMB_LOG2_BITS) |
55 | | |
56 | | typedef int32_t slimb_t; |
57 | | typedef uint32_t limb_t; |
58 | | typedef uint64_t dlimb_t; |
59 | | |
60 | | #define LIMB_DIGITS 9 |
61 | | |
62 | | #define JS_RADIX_MAX 36 |
63 | | |
64 | 1 | #define DBIGNUM_LEN_MAX 52 /* ~ 2^(1072+53)*36^100 (dtoa) */ |
65 | 0 | #define MANT_LEN_MAX 18 /* < 36^100 */ |
66 | | |
67 | | typedef intptr_t mp_size_t; |
68 | | |
69 | | /* the represented number is sum(i, tab[i]*2^(LIMB_BITS * i)) */ |
70 | | typedef struct { |
71 | | int len; /* >= 1 */ |
72 | | limb_t tab[]; |
73 | | } mpb_t; |
74 | | |
75 | | static limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n) |
76 | 0 | { |
77 | 0 | size_t i; |
78 | 0 | limb_t k, a; |
79 | |
|
80 | 0 | k=b; |
81 | 0 | for(i=0;i<n;i++) { |
82 | 0 | if (k == 0) |
83 | 0 | break; |
84 | 0 | a = tab[i] + k; |
85 | 0 | k = (a < k); |
86 | 0 | tab[i] = a; |
87 | 0 | } |
88 | 0 | return k; |
89 | 0 | } |
90 | | |
91 | | /* tabr[] = taba[] * b + l. Return the high carry */ |
92 | | static limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n, |
93 | | limb_t b, limb_t l) |
94 | 0 | { |
95 | 0 | limb_t i; |
96 | 0 | dlimb_t t; |
97 | |
|
98 | 0 | for(i = 0; i < n; i++) { |
99 | 0 | t = (dlimb_t)taba[i] * (dlimb_t)b + l; |
100 | 0 | tabr[i] = t; |
101 | 0 | l = t >> LIMB_BITS; |
102 | 0 | } |
103 | 0 | return l; |
104 | 0 | } |
105 | | |
106 | | /* WARNING: d must be >= 2^(LIMB_BITS-1) */ |
107 | | static inline limb_t udiv1norm_init(limb_t d) |
108 | 0 | { |
109 | 0 | limb_t a0, a1; |
110 | 0 | a1 = -d - 1; |
111 | 0 | a0 = -1; |
112 | 0 | return (((dlimb_t)a1 << LIMB_BITS) | a0) / d; |
113 | 0 | } |
114 | | |
115 | | /* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0 |
116 | | / d' with 0 <= a1 < d. */ |
117 | | static inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0, |
118 | | limb_t d, limb_t d_inv) |
119 | 0 | { |
120 | 0 | limb_t n1m, n_adj, q, r, ah; |
121 | 0 | dlimb_t a; |
122 | 0 | n1m = ((slimb_t)a0 >> (LIMB_BITS - 1)); |
123 | 0 | n_adj = a0 + (n1m & d); |
124 | 0 | a = (dlimb_t)d_inv * (a1 - n1m) + n_adj; |
125 | 0 | q = (a >> LIMB_BITS) + a1; |
126 | | /* compute a - q * r and update q so that the remainder is between |
127 | | 0 and d - 1 */ |
128 | 0 | a = ((dlimb_t)a1 << LIMB_BITS) | a0; |
129 | 0 | a = a - (dlimb_t)q * d - d; |
130 | 0 | ah = a >> LIMB_BITS; |
131 | 0 | q += 1 + ah; |
132 | 0 | r = (limb_t)a + (ah & d); |
133 | 0 | *pr = r; |
134 | 0 | return q; |
135 | 0 | } |
136 | | |
137 | | static limb_t mp_div1(limb_t *tabr, const limb_t *taba, limb_t n, |
138 | | limb_t b, limb_t r) |
139 | 0 | { |
140 | 0 | slimb_t i; |
141 | 0 | dlimb_t a1; |
142 | 0 | for(i = n - 1; i >= 0; i--) { |
143 | 0 | a1 = ((dlimb_t)r << LIMB_BITS) | taba[i]; |
144 | 0 | tabr[i] = a1 / b; |
145 | 0 | r = a1 % b; |
146 | 0 | } |
147 | 0 | return r; |
148 | 0 | } |
149 | | |
150 | | /* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). |
151 | | 1 <= shift <= LIMB_BITS - 1 */ |
152 | | static limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, |
153 | | int shift, limb_t high) |
154 | 0 | { |
155 | 0 | mp_size_t i; |
156 | 0 | limb_t l, a; |
157 | |
|
158 | 0 | assert(shift >= 1 && shift < LIMB_BITS); |
159 | 0 | l = high; |
160 | 0 | for(i = n - 1; i >= 0; i--) { |
161 | 0 | a = tab[i]; |
162 | 0 | tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift)); |
163 | 0 | l = a; |
164 | 0 | } |
165 | 0 | return l & (((limb_t)1 << shift) - 1); |
166 | 0 | } |
167 | | |
168 | | /* r = (a << shift) + low. 1 <= shift <= LIMB_BITS - 1, 0 <= low < |
169 | | 2^shift. */ |
170 | | static limb_t mp_shl(limb_t *tab_r, const limb_t *tab, mp_size_t n, |
171 | | int shift, limb_t low) |
172 | 0 | { |
173 | 0 | mp_size_t i; |
174 | 0 | limb_t l, a; |
175 | |
|
176 | 0 | assert(shift >= 1 && shift < LIMB_BITS); |
177 | 0 | l = low; |
178 | 0 | for(i = 0; i < n; i++) { |
179 | 0 | a = tab[i]; |
180 | 0 | tab_r[i] = (a << shift) | l; |
181 | 0 | l = (a >> (LIMB_BITS - shift)); |
182 | 0 | } |
183 | 0 | return l; |
184 | 0 | } |
185 | | |
186 | | static no_inline limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n, |
187 | | limb_t b, limb_t r, limb_t b_inv, int shift) |
188 | 0 | { |
189 | 0 | slimb_t i; |
190 | |
|
191 | 0 | if (shift != 0) { |
192 | 0 | r = (r << shift) | mp_shl(tabr, taba, n, shift, 0); |
193 | 0 | } |
194 | 0 | for(i = n - 1; i >= 0; i--) { |
195 | 0 | tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv); |
196 | 0 | } |
197 | 0 | r >>= shift; |
198 | 0 | return r; |
199 | 0 | } |
200 | | |
201 | | static __maybe_unused void mpb_dump(const char *str, const mpb_t *a) |
202 | 0 | { |
203 | 0 | int i; |
204 | 0 | |
205 | 0 | printf("%s= 0x", str); |
206 | 0 | for(i = a->len - 1; i >= 0; i--) { |
207 | 0 | printf("%08x", a->tab[i]); |
208 | 0 | if (i != 0) |
209 | 0 | printf("_"); |
210 | 0 | } |
211 | 0 | printf("\n"); |
212 | 0 | } |
213 | | |
214 | | static void mpb_renorm(mpb_t *r) |
215 | 1 | { |
216 | 1 | while (r->len > 1 && r->tab[r->len - 1] == 0) |
217 | 0 | r->len--; |
218 | 1 | } |
219 | | |
220 | | #ifdef USE_POW5_TABLE |
221 | | static const uint32_t pow5_table[17] = { |
222 | | 0x00000005, 0x00000019, 0x0000007d, 0x00000271, |
223 | | 0x00000c35, 0x00003d09, 0x0001312d, 0x0005f5e1, |
224 | | 0x001dcd65, 0x009502f9, 0x02e90edd, 0x0e8d4a51, |
225 | | 0x48c27395, 0x6bcc41e9, 0x1afd498d, 0x86f26fc1, |
226 | | 0xa2bc2ec5, |
227 | | }; |
228 | | |
229 | | static const uint8_t pow5h_table[4] = { |
230 | | 0x00000001, 0x00000007, 0x00000023, 0x000000b1, |
231 | | }; |
232 | | |
233 | | static const uint32_t pow5_inv_table[13] = { |
234 | | 0x99999999, 0x47ae147a, 0x0624dd2f, 0xa36e2eb1, |
235 | | 0x4f8b588e, 0x0c6f7a0b, 0xad7f29ab, 0x5798ee23, |
236 | | 0x12e0be82, 0xb7cdfd9d, 0x5fd7fe17, 0x19799812, |
237 | | 0xc25c2684, |
238 | | }; |
239 | | #endif |
240 | | |
241 | | /* return a^b */ |
242 | | static uint64_t pow_ui(uint32_t a, uint32_t b) |
243 | 0 | { |
244 | 0 | int i, n_bits; |
245 | 0 | uint64_t r; |
246 | 0 | if (b == 0) |
247 | 0 | return 1; |
248 | 0 | if (b == 1) |
249 | 0 | return a; |
250 | 0 | #ifdef USE_POW5_TABLE |
251 | 0 | if ((a == 5 || a == 10) && b <= 17) { |
252 | 0 | r = pow5_table[b - 1]; |
253 | 0 | if (b >= 14) { |
254 | 0 | r |= (uint64_t)pow5h_table[b - 14] << 32; |
255 | 0 | } |
256 | 0 | if (a == 10) |
257 | 0 | r <<= b; |
258 | 0 | return r; |
259 | 0 | } |
260 | 0 | #endif |
261 | 0 | r = a; |
262 | 0 | n_bits = 32 - clz32(b); |
263 | 0 | for(i = n_bits - 2; i >= 0; i--) { |
264 | 0 | r *= r; |
265 | 0 | if ((b >> i) & 1) |
266 | 0 | r *= a; |
267 | 0 | } |
268 | 0 | return r; |
269 | 0 | } |
270 | | |
271 | | static uint32_t pow_ui_inv(uint32_t *pr_inv, int *pshift, uint32_t a, uint32_t b) |
272 | 0 | { |
273 | 0 | uint32_t r_inv, r; |
274 | 0 | int shift; |
275 | 0 | #ifdef USE_POW5_TABLE |
276 | 0 | if (a == 5 && b >= 1 && b <= 13) { |
277 | 0 | r = pow5_table[b - 1]; |
278 | 0 | shift = clz32(r); |
279 | 0 | r <<= shift; |
280 | 0 | r_inv = pow5_inv_table[b - 1]; |
281 | 0 | } else |
282 | 0 | #endif |
283 | 0 | { |
284 | 0 | r = pow_ui(a, b); |
285 | 0 | shift = clz32(r); |
286 | 0 | r <<= shift; |
287 | 0 | r_inv = udiv1norm_init(r); |
288 | 0 | } |
289 | 0 | *pshift = shift; |
290 | 0 | *pr_inv = r_inv; |
291 | 0 | return r; |
292 | 0 | } |
293 | | |
294 | | enum { |
295 | | JS_RNDN, /* round to nearest, ties to even */ |
296 | | JS_RNDNA, /* round to nearest, ties away from zero */ |
297 | | JS_RNDZ, |
298 | | }; |
299 | | |
300 | | static int mpb_get_bit(const mpb_t *r, int k) |
301 | 0 | { |
302 | 0 | int l; |
303 | | |
304 | 0 | l = (unsigned)k / LIMB_BITS; |
305 | 0 | k = k & (LIMB_BITS - 1); |
306 | 0 | if (l >= r->len) |
307 | 0 | return 0; |
308 | 0 | else |
309 | 0 | return (r->tab[l] >> k) & 1; |
310 | 0 | } |
311 | | |
312 | | /* compute round(r / 2^shift). 'shift' can be negative */ |
313 | | static void mpb_shr_round(mpb_t *r, int shift, int rnd_mode) |
314 | 0 | { |
315 | 0 | int l, i; |
316 | |
|
317 | 0 | if (shift == 0) |
318 | 0 | return; |
319 | 0 | if (shift < 0) { |
320 | 0 | shift = -shift; |
321 | 0 | l = (unsigned)shift / LIMB_BITS; |
322 | 0 | shift = shift & (LIMB_BITS - 1); |
323 | 0 | if (shift != 0) { |
324 | 0 | r->tab[r->len] = mp_shl(r->tab, r->tab, r->len, shift, 0); |
325 | 0 | r->len++; |
326 | 0 | mpb_renorm(r); |
327 | 0 | } |
328 | 0 | if (l > 0) { |
329 | 0 | for(i = r->len - 1; i >= 0; i--) |
330 | 0 | r->tab[i + l] = r->tab[i]; |
331 | 0 | for(i = 0; i < l; i++) |
332 | 0 | r->tab[i] = 0; |
333 | 0 | r->len += l; |
334 | 0 | } |
335 | 0 | } else { |
336 | 0 | limb_t bit1, bit2; |
337 | 0 | int k, add_one; |
338 | | |
339 | 0 | switch(rnd_mode) { |
340 | 0 | default: |
341 | 0 | case JS_RNDZ: |
342 | 0 | add_one = 0; |
343 | 0 | break; |
344 | 0 | case JS_RNDN: |
345 | 0 | case JS_RNDNA: |
346 | 0 | bit1 = mpb_get_bit(r, shift - 1); |
347 | 0 | if (bit1) { |
348 | 0 | if (rnd_mode == JS_RNDNA) { |
349 | 0 | bit2 = 1; |
350 | 0 | } else { |
351 | | /* bit2 = oring of all the bits after bit1 */ |
352 | 0 | bit2 = 0; |
353 | 0 | if (shift >= 2) { |
354 | 0 | k = shift - 1; |
355 | 0 | l = (unsigned)k / LIMB_BITS; |
356 | 0 | k = k & (LIMB_BITS - 1); |
357 | 0 | for(i = 0; i < min_int(l, r->len); i++) |
358 | 0 | bit2 |= r->tab[i]; |
359 | 0 | if (l < r->len) |
360 | 0 | bit2 |= r->tab[l] & (((limb_t)1 << k) - 1); |
361 | 0 | } |
362 | 0 | } |
363 | 0 | if (bit2) { |
364 | 0 | add_one = 1; |
365 | 0 | } else { |
366 | | /* round to even */ |
367 | 0 | add_one = mpb_get_bit(r, shift); |
368 | 0 | } |
369 | 0 | } else { |
370 | 0 | add_one = 0; |
371 | 0 | } |
372 | 0 | break; |
373 | 0 | } |
374 | | |
375 | 0 | l = (unsigned)shift / LIMB_BITS; |
376 | 0 | shift = shift & (LIMB_BITS - 1); |
377 | 0 | if (l >= r->len) { |
378 | 0 | r->len = 1; |
379 | 0 | r->tab[0] = add_one; |
380 | 0 | } else { |
381 | 0 | if (l > 0) { |
382 | 0 | r->len -= l; |
383 | 0 | for(i = 0; i < r->len; i++) |
384 | 0 | r->tab[i] = r->tab[i + l]; |
385 | 0 | } |
386 | 0 | if (shift != 0) { |
387 | 0 | mp_shr(r->tab, r->tab, r->len, shift, 0); |
388 | 0 | mpb_renorm(r); |
389 | 0 | } |
390 | 0 | if (add_one) { |
391 | 0 | limb_t a; |
392 | 0 | a = mp_add_ui(r->tab, 1, r->len); |
393 | 0 | if (a) |
394 | 0 | r->tab[r->len++] = a; |
395 | 0 | } |
396 | 0 | } |
397 | 0 | } |
398 | 0 | } |
399 | | |
400 | | /* return -1, 0 or 1 */ |
401 | | static int mpb_cmp(const mpb_t *a, const mpb_t *b) |
402 | 0 | { |
403 | 0 | mp_size_t i; |
404 | 0 | if (a->len < b->len) |
405 | 0 | return -1; |
406 | 0 | else if (a->len > b->len) |
407 | 0 | return 1; |
408 | 0 | for(i = a->len - 1; i >= 0; i--) { |
409 | 0 | if (a->tab[i] != b->tab[i]) { |
410 | 0 | if (a->tab[i] < b->tab[i]) |
411 | 0 | return -1; |
412 | 0 | else |
413 | 0 | return 1; |
414 | 0 | } |
415 | 0 | } |
416 | 0 | return 0; |
417 | 0 | } |
418 | | |
419 | | static void mpb_set_u64(mpb_t *r, uint64_t m) |
420 | 0 | { |
421 | | #if LIMB_BITS == 64 |
422 | | r->tab[0] = m; |
423 | | r->len = 1; |
424 | | #else |
425 | 0 | r->tab[0] = m; |
426 | 0 | r->tab[1] = m >> LIMB_BITS; |
427 | 0 | if (r->tab[1] == 0) |
428 | 0 | r->len = 1; |
429 | 0 | else |
430 | 0 | r->len = 2; |
431 | 0 | #endif |
432 | 0 | } |
433 | | |
434 | | static uint64_t mpb_get_u64(mpb_t *r) |
435 | 0 | { |
436 | | #if LIMB_BITS == 64 |
437 | | return r->tab[0]; |
438 | | #else |
439 | 0 | if (r->len == 1) { |
440 | 0 | return r->tab[0]; |
441 | 0 | } else { |
442 | 0 | return r->tab[0] | ((uint64_t)r->tab[1] << LIMB_BITS); |
443 | 0 | } |
444 | 0 | #endif |
445 | 0 | } |
446 | | |
447 | | /* floor_log2() = position of the first non zero bit or -1 if zero. */ |
448 | | static int mpb_floor_log2(mpb_t *a) |
449 | 0 | { |
450 | 0 | limb_t v; |
451 | 0 | v = a->tab[a->len - 1]; |
452 | 0 | if (v == 0) |
453 | 0 | return -1; |
454 | 0 | else |
455 | 0 | return a->len * LIMB_BITS - 1 - clz32(v); |
456 | 0 | } |
457 | | |
458 | 0 | #define MUL_LOG2_RADIX_BASE_LOG2 24 |
459 | | |
460 | | /* round((1 << MUL_LOG2_RADIX_BASE_LOG2)/log2(i + 2)) */ |
461 | | static const uint32_t mul_log2_radix_table[JS_RADIX_MAX - 1] = { |
462 | | 0x000000, 0xa1849d, 0x000000, 0x6e40d2, |
463 | | 0x6308c9, 0x5b3065, 0x000000, 0x50c24e, |
464 | | 0x4d104d, 0x4a0027, 0x4768ce, 0x452e54, |
465 | | 0x433d00, 0x418677, 0x000000, 0x3ea16b, |
466 | | 0x3d645a, 0x3c43c2, 0x3b3b9a, 0x3a4899, |
467 | | 0x39680b, 0x3897b3, 0x37d5af, 0x372069, |
468 | | 0x367686, 0x35d6df, 0x354072, 0x34b261, |
469 | | 0x342bea, 0x33ac62, 0x000000, 0x32bfd9, |
470 | | 0x3251dd, 0x31e8d6, 0x318465, |
471 | | }; |
472 | | |
473 | | /* return floor(a / log2(radix)) for -2048 <= a <= 2047 */ |
474 | | static int mul_log2_radix(int a, int radix) |
475 | 0 | { |
476 | 0 | int radix_bits, mult; |
477 | |
|
478 | 0 | if ((radix & (radix - 1)) == 0) { |
479 | | /* if the radix is a power of two better to do it exactly */ |
480 | 0 | radix_bits = 31 - clz32(radix); |
481 | 0 | if (a < 0) |
482 | 0 | a -= radix_bits - 1; |
483 | 0 | return a / radix_bits; |
484 | 0 | } else { |
485 | 0 | mult = mul_log2_radix_table[radix - 2]; |
486 | 0 | return ((int64_t)a * mult) >> MUL_LOG2_RADIX_BASE_LOG2; |
487 | 0 | } |
488 | 0 | } |
489 | | |
490 | | #if 0 |
491 | | static void build_mul_log2_radix_table(void) |
492 | | { |
493 | | int base, radix, mult, col, base_log2; |
494 | | |
495 | | base_log2 = 24; |
496 | | base = 1 << base_log2; |
497 | | col = 0; |
498 | | for(radix = 2; radix <= 36; radix++) { |
499 | | if ((radix & (radix - 1)) == 0) |
500 | | mult = 0; |
501 | | else |
502 | | mult = lrint((double)base / log2(radix)); |
503 | | printf("0x%06x, ", mult); |
504 | | if (++col == 4) { |
505 | | printf("\n"); |
506 | | col = 0; |
507 | | } |
508 | | } |
509 | | printf("\n"); |
510 | | } |
511 | | |
512 | | static void mul_log2_radix_test(void) |
513 | | { |
514 | | int radix, i, ref, r; |
515 | | |
516 | | for(radix = 2; radix <= 36; radix++) { |
517 | | for(i = -2048; i <= 2047; i++) { |
518 | | ref = (int)floor((double)i / log2(radix)); |
519 | | r = mul_log2_radix(i, radix); |
520 | | if (ref != r) { |
521 | | printf("ERROR: radix=%d i=%d r=%d ref=%d\n", |
522 | | radix, i, r, ref); |
523 | | exit(1); |
524 | | } |
525 | | } |
526 | | } |
527 | | if (0) |
528 | | build_mul_log2_radix_table(); |
529 | | } |
530 | | #endif |
531 | | |
532 | | static void u32toa_len(char *buf, uint32_t n, size_t len) |
533 | 0 | { |
534 | 0 | int digit, i; |
535 | 0 | for(i = len - 1; i >= 0; i--) { |
536 | 0 | digit = n % 10; |
537 | 0 | n = n / 10; |
538 | 0 | buf[i] = digit + '0'; |
539 | 0 | } |
540 | 0 | } |
541 | | |
542 | | /* for power of 2 radixes. len >= 1 */ |
543 | | static void u64toa_bin_len(char *buf, uint64_t n, unsigned int radix_bits, int len) |
544 | 0 | { |
545 | 0 | int digit, i; |
546 | 0 | unsigned int mask; |
547 | |
|
548 | 0 | mask = (1 << radix_bits) - 1; |
549 | 0 | for(i = len - 1; i >= 0; i--) { |
550 | 0 | digit = n & mask; |
551 | 0 | n >>= radix_bits; |
552 | 0 | if (digit < 10) |
553 | 0 | digit += '0'; |
554 | 0 | else |
555 | 0 | digit += 'a' - 10; |
556 | 0 | buf[i] = digit; |
557 | 0 | } |
558 | 0 | } |
559 | | |
560 | | /* len >= 1. 2 <= radix <= 36 */ |
561 | | static void limb_to_a(char *buf, limb_t n, unsigned int radix, int len) |
562 | 0 | { |
563 | 0 | int digit, i; |
564 | |
|
565 | 0 | if (radix == 10) { |
566 | | /* specific case with constant divisor */ |
567 | 0 | #if LIMB_BITS == 32 |
568 | 0 | u32toa_len(buf, n, len); |
569 | | #else |
570 | | /* XXX: optimize */ |
571 | | for(i = len - 1; i >= 0; i--) { |
572 | | digit = (limb_t)n % 10; |
573 | | n = (limb_t)n / 10; |
574 | | buf[i] = digit + '0'; |
575 | | } |
576 | | #endif |
577 | 0 | } else { |
578 | 0 | for(i = len - 1; i >= 0; i--) { |
579 | 0 | digit = (limb_t)n % radix; |
580 | 0 | n = (limb_t)n / radix; |
581 | 0 | if (digit < 10) |
582 | 0 | digit += '0'; |
583 | 0 | else |
584 | 0 | digit += 'a' - 10; |
585 | 0 | buf[i] = digit; |
586 | 0 | } |
587 | 0 | } |
588 | 0 | } |
589 | | |
590 | | size_t u32toa(char *buf, uint32_t n) |
591 | 0 | { |
592 | 0 | char buf1[10], *q; |
593 | 0 | size_t len; |
594 | | |
595 | 0 | q = buf1 + sizeof(buf1); |
596 | 0 | do { |
597 | 0 | *--q = n % 10 + '0'; |
598 | 0 | n /= 10; |
599 | 0 | } while (n != 0); |
600 | 0 | len = buf1 + sizeof(buf1) - q; |
601 | 0 | memcpy(buf, q, len); |
602 | 0 | return len; |
603 | 0 | } |
604 | | |
605 | | size_t i32toa(char *buf, int32_t n) |
606 | 0 | { |
607 | 0 | if (n >= 0) { |
608 | 0 | return u32toa(buf, n); |
609 | 0 | } else { |
610 | 0 | buf[0] = '-'; |
611 | 0 | return u32toa(buf + 1, -(uint32_t)n) + 1; |
612 | 0 | } |
613 | 0 | } |
614 | | |
615 | | #ifdef USE_FAST_INT |
616 | | size_t u64toa(char *buf, uint64_t n) |
617 | 0 | { |
618 | 0 | if (n < 0x100000000) { |
619 | 0 | return u32toa(buf, n); |
620 | 0 | } else { |
621 | 0 | uint64_t n1; |
622 | 0 | char *q = buf; |
623 | 0 | uint32_t n2; |
624 | | |
625 | 0 | n1 = n / 1000000000; |
626 | 0 | n %= 1000000000; |
627 | 0 | if (n1 >= 0x100000000) { |
628 | 0 | n2 = n1 / 1000000000; |
629 | 0 | n1 = n1 % 1000000000; |
630 | | /* at most two digits */ |
631 | 0 | if (n2 >= 10) { |
632 | 0 | *q++ = n2 / 10 + '0'; |
633 | 0 | n2 %= 10; |
634 | 0 | } |
635 | 0 | *q++ = n2 + '0'; |
636 | 0 | u32toa_len(q, n1, 9); |
637 | 0 | q += 9; |
638 | 0 | } else { |
639 | 0 | q += u32toa(q, n1); |
640 | 0 | } |
641 | 0 | u32toa_len(q, n, 9); |
642 | 0 | q += 9; |
643 | 0 | return q - buf; |
644 | 0 | } |
645 | 0 | } |
646 | | |
647 | | size_t i64toa(char *buf, int64_t n) |
648 | 0 | { |
649 | 0 | if (n >= 0) { |
650 | 0 | return u64toa(buf, n); |
651 | 0 | } else { |
652 | 0 | buf[0] = '-'; |
653 | 0 | return u64toa(buf + 1, -(uint64_t)n) + 1; |
654 | 0 | } |
655 | 0 | } |
656 | | |
657 | | /* XXX: only tested for 1 <= n < 2^53 */ |
658 | | size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix) |
659 | 0 | { |
660 | 0 | int radix_bits, l; |
661 | 0 | if (likely(radix == 10)) |
662 | 0 | return u64toa(buf, n); |
663 | 0 | if ((radix & (radix - 1)) == 0) { |
664 | 0 | radix_bits = 31 - clz32(radix); |
665 | 0 | if (n == 0) |
666 | 0 | l = 1; |
667 | 0 | else |
668 | 0 | l = (64 - clz64(n) + radix_bits - 1) / radix_bits; |
669 | 0 | u64toa_bin_len(buf, n, radix_bits, l); |
670 | 0 | return l; |
671 | 0 | } else { |
672 | 0 | char buf1[41], *q; /* maximum length for radix = 3 */ |
673 | 0 | size_t len; |
674 | 0 | int digit; |
675 | 0 | q = buf1 + sizeof(buf1); |
676 | 0 | do { |
677 | 0 | digit = n % radix; |
678 | 0 | n /= radix; |
679 | 0 | if (digit < 10) |
680 | 0 | digit += '0'; |
681 | 0 | else |
682 | 0 | digit += 'a' - 10; |
683 | 0 | *--q = digit; |
684 | 0 | } while (n != 0); |
685 | 0 | len = buf1 + sizeof(buf1) - q; |
686 | 0 | memcpy(buf, q, len); |
687 | 0 | return len; |
688 | 0 | } |
689 | 0 | } |
690 | | |
691 | | size_t i64toa_radix(char *buf, int64_t n, unsigned int radix) |
692 | 0 | { |
693 | 0 | if (n >= 0) { |
694 | 0 | return u64toa_radix(buf, n, radix); |
695 | 0 | } else { |
696 | 0 | buf[0] = '-'; |
697 | 0 | return u64toa_radix(buf + 1, -(uint64_t)n, radix) + 1; |
698 | 0 | } |
699 | 0 | } |
700 | | #endif /* USE_FAST_INT */ |
701 | | |
702 | | static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = { |
703 | | #if LIMB_BITS == 32 |
704 | | 32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
705 | | #else |
706 | | 64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12, |
707 | | #endif |
708 | | }; |
709 | | |
710 | | static const uint32_t radix_base_table[JS_RADIX_MAX - 1] = { |
711 | | 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395, |
712 | | 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91, |
713 | | 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021, |
714 | | 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571, |
715 | | 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d, |
716 | | 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51, |
717 | | 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899, |
718 | | 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1, |
719 | | 0x5c13d840, 0x6d91b519, 0x81bf1000, |
720 | | }; |
721 | | |
722 | | /* XXX: remove the table ? */ |
723 | | static uint8_t dtoa_max_digits_table[JS_RADIX_MAX - 1] = { |
724 | | 54, 35, 28, 24, 22, 20, 19, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, |
725 | | }; |
726 | | |
727 | | /* we limit the maximum number of significant digits for atod to about |
728 | | 128 bits of precision for non power of two bases. The only |
729 | | requirement for Javascript is at least 20 digits in base 10. For |
730 | | power of two bases, we do an exact rounding in all the cases. */ |
731 | | static uint8_t atod_max_digits_table[JS_RADIX_MAX - 1] = { |
732 | | 64, 80, 32, 55, 49, 45, 21, 40, 38, 37, 35, 34, 33, 32, 16, 31, 30, 30, 29, 29, 28, 28, 27, 27, 27, 26, 26, 26, 26, 25, 12, 25, 25, 24, 24, |
733 | | }; |
734 | | |
735 | | /* if abs(d) >= B^max_exponent, it is an overflow */ |
736 | | static const int16_t max_exponent[JS_RADIX_MAX - 1] = { |
737 | | 1024, 647, 512, 442, 397, 365, 342, 324, |
738 | | 309, 297, 286, 277, 269, 263, 256, 251, |
739 | | 246, 242, 237, 234, 230, 227, 224, 221, |
740 | | 218, 216, 214, 211, 209, 207, 205, 203, |
741 | | 202, 200, 199, |
742 | | }; |
743 | | |
744 | | /* if abs(d) <= B^min_exponent, it is an underflow */ |
745 | | static const int16_t min_exponent[JS_RADIX_MAX - 1] = { |
746 | | -1075, -679, -538, -463, -416, -383, -359, -340, |
747 | | -324, -311, -300, -291, -283, -276, -269, -263, |
748 | | -258, -254, -249, -245, -242, -238, -235, -232, |
749 | | -229, -227, -224, -222, -220, -217, -215, -214, |
750 | | -212, -210, -208, |
751 | | }; |
752 | | |
753 | | #if 0 |
754 | | void build_tables(void) |
755 | | { |
756 | | int r, j, radix, n, col, i; |
757 | | |
758 | | /* radix_base_table */ |
759 | | for(radix = 2; radix <= 36; radix++) { |
760 | | r = 1; |
761 | | for(j = 0; j < digits_per_limb_table[radix - 2]; j++) { |
762 | | r *= radix; |
763 | | } |
764 | | printf(" 0x%08x,", r); |
765 | | if ((radix % 4) == 1) |
766 | | printf("\n"); |
767 | | } |
768 | | printf("\n"); |
769 | | |
770 | | /* dtoa_max_digits_table */ |
771 | | for(radix = 2; radix <= 36; radix++) { |
772 | | /* Note: over estimated when the radix is a power of two */ |
773 | | printf(" %d,", 1 + (int)ceil(53.0 / log2(radix))); |
774 | | } |
775 | | printf("\n"); |
776 | | |
777 | | /* atod_max_digits_table */ |
778 | | for(radix = 2; radix <= 36; radix++) { |
779 | | if ((radix & (radix - 1)) == 0) { |
780 | | /* 64 bits is more than enough */ |
781 | | n = (int)floor(64.0 / log2(radix)); |
782 | | } else { |
783 | | n = (int)floor(128.0 / log2(radix)); |
784 | | } |
785 | | printf(" %d,", n); |
786 | | } |
787 | | printf("\n"); |
788 | | |
789 | | printf("static const int16_t max_exponent[JS_RADIX_MAX - 1] = {\n"); |
790 | | col = 0; |
791 | | for(radix = 2; radix <= 36; radix++) { |
792 | | printf("%5d, ", (int)ceil(1024 / log2(radix))); |
793 | | if (++col == 8) { |
794 | | col = 0; |
795 | | printf("\n"); |
796 | | } |
797 | | } |
798 | | printf("\n};\n\n"); |
799 | | |
800 | | printf("static const int16_t min_exponent[JS_RADIX_MAX - 1] = {\n"); |
801 | | col = 0; |
802 | | for(radix = 2; radix <= 36; radix++) { |
803 | | printf("%5d, ", (int)floor(-1075 / log2(radix))); |
804 | | if (++col == 8) { |
805 | | col = 0; |
806 | | printf("\n"); |
807 | | } |
808 | | } |
809 | | printf("\n};\n\n"); |
810 | | |
811 | | printf("static const uint32_t pow5_table[16] = {\n"); |
812 | | col = 0; |
813 | | for(i = 2; i <= 17; i++) { |
814 | | r = 1; |
815 | | for(j = 0; j < i; j++) { |
816 | | r *= 5; |
817 | | } |
818 | | printf("0x%08x, ", r); |
819 | | if (++col == 4) { |
820 | | col = 0; |
821 | | printf("\n"); |
822 | | } |
823 | | } |
824 | | printf("\n};\n\n"); |
825 | | |
826 | | /* high part */ |
827 | | printf("static const uint8_t pow5h_table[4] = {\n"); |
828 | | col = 0; |
829 | | for(i = 14; i <= 17; i++) { |
830 | | uint64_t r1; |
831 | | r1 = 1; |
832 | | for(j = 0; j < i; j++) { |
833 | | r1 *= 5; |
834 | | } |
835 | | printf("0x%08x, ", (uint32_t)(r1 >> 32)); |
836 | | if (++col == 4) { |
837 | | col = 0; |
838 | | printf("\n"); |
839 | | } |
840 | | } |
841 | | printf("\n};\n\n"); |
842 | | } |
843 | | #endif |
844 | | |
845 | | /* n_digits >= 1. 0 <= dot_pos <= n_digits. If dot_pos == n_digits, |
846 | | the dot is not displayed. 'a' is modified. */ |
847 | | static int output_digits(char *buf, |
848 | | mpb_t *a, int radix, int n_digits1, |
849 | | int dot_pos) |
850 | 0 | { |
851 | 0 | int n_digits, digits_per_limb, radix_bits, n, len; |
852 | |
|
853 | 0 | n_digits = n_digits1; |
854 | 0 | if ((radix & (radix - 1)) == 0) { |
855 | | /* radix = 2^radix_bits */ |
856 | 0 | radix_bits = 31 - clz32(radix); |
857 | 0 | } else { |
858 | 0 | radix_bits = 0; |
859 | 0 | } |
860 | 0 | digits_per_limb = digits_per_limb_table[radix - 2]; |
861 | 0 | if (radix_bits != 0) { |
862 | 0 | for(;;) { |
863 | 0 | n = min_int(n_digits, digits_per_limb); |
864 | 0 | n_digits -= n; |
865 | 0 | u64toa_bin_len(buf + n_digits, a->tab[0], radix_bits, n); |
866 | 0 | if (n_digits == 0) |
867 | 0 | break; |
868 | 0 | mpb_shr_round(a, digits_per_limb * radix_bits, JS_RNDZ); |
869 | 0 | } |
870 | 0 | } else { |
871 | 0 | limb_t r; |
872 | 0 | while (n_digits != 0) { |
873 | 0 | n = min_int(n_digits, digits_per_limb); |
874 | 0 | n_digits -= n; |
875 | 0 | r = mp_div1(a->tab, a->tab, a->len, radix_base_table[radix - 2], 0); |
876 | 0 | mpb_renorm(a); |
877 | 0 | limb_to_a(buf + n_digits, r, radix, n); |
878 | 0 | } |
879 | 0 | } |
880 | | |
881 | | /* add the dot */ |
882 | 0 | len = n_digits1; |
883 | 0 | if (dot_pos != n_digits1) { |
884 | 0 | memmove(buf + dot_pos + 1, buf + dot_pos, n_digits1 - dot_pos); |
885 | 0 | buf[dot_pos] = '.'; |
886 | 0 | len++; |
887 | 0 | } |
888 | 0 | return len; |
889 | 0 | } |
890 | | |
891 | | /* return (a, e_offset) such that a = a * (radix1*2^radix_shift)^f * |
892 | | 2^-e_offset. 'f' can be negative. */ |
893 | | static int mul_pow(mpb_t *a, int radix1, int radix_shift, int f, BOOL is_int, int e) |
894 | 0 | { |
895 | 0 | int e_offset, d, n, n0; |
896 | |
|
897 | 0 | e_offset = -f * radix_shift; |
898 | 0 | if (radix1 != 1) { |
899 | 0 | d = digits_per_limb_table[radix1 - 2]; |
900 | 0 | if (f >= 0) { |
901 | 0 | limb_t h, b; |
902 | | |
903 | 0 | b = 0; |
904 | 0 | n0 = 0; |
905 | 0 | while (f != 0) { |
906 | 0 | n = min_int(f, d); |
907 | 0 | if (n != n0) { |
908 | 0 | b = pow_ui(radix1, n); |
909 | 0 | n0 = n; |
910 | 0 | } |
911 | 0 | h = mp_mul1(a->tab, a->tab, a->len, b, 0); |
912 | 0 | if (h != 0) { |
913 | 0 | a->tab[a->len++] = h; |
914 | 0 | } |
915 | 0 | f -= n; |
916 | 0 | } |
917 | 0 | } else { |
918 | 0 | int extra_bits, l, shift; |
919 | 0 | limb_t r, rem, b, b_inv; |
920 | | |
921 | 0 | f = -f; |
922 | 0 | l = (f + d - 1) / d; /* high bound for the number of limbs (XXX: make it better) */ |
923 | 0 | e_offset += l * LIMB_BITS; |
924 | 0 | if (!is_int) { |
925 | | /* at least 'e' bits are needed in the final result for rounding */ |
926 | 0 | extra_bits = max_int(e - mpb_floor_log2(a), 0); |
927 | 0 | } else { |
928 | | /* at least two extra bits are needed in the final result |
929 | | for rounding */ |
930 | 0 | extra_bits = max_int(2 + e - e_offset, 0); |
931 | 0 | } |
932 | 0 | e_offset += extra_bits; |
933 | 0 | mpb_shr_round(a, -(l * LIMB_BITS + extra_bits), JS_RNDZ); |
934 | | |
935 | 0 | b = 0; |
936 | 0 | b_inv = 0; |
937 | 0 | shift = 0; |
938 | 0 | n0 = 0; |
939 | 0 | rem = 0; |
940 | 0 | while (f != 0) { |
941 | 0 | n = min_int(f, d); |
942 | 0 | if (n != n0) { |
943 | 0 | b = pow_ui_inv(&b_inv, &shift, radix1, n); |
944 | 0 | n0 = n; |
945 | 0 | } |
946 | 0 | r = mp_div1norm(a->tab, a->tab, a->len, b, 0, b_inv, shift); |
947 | 0 | rem |= r; |
948 | 0 | mpb_renorm(a); |
949 | 0 | f -= n; |
950 | 0 | } |
951 | | /* if the remainder is non zero, use it for rounding */ |
952 | 0 | a->tab[0] |= (rem != 0); |
953 | 0 | } |
954 | 0 | } |
955 | 0 | return e_offset; |
956 | 0 | } |
957 | | |
958 | | /* tmp1 = round(m*2^e*radix^f). 'tmp0' is a temporary storage */ |
959 | | static void mul_pow_round(mpb_t *tmp1, uint64_t m, int e, int radix1, int radix_shift, int f, |
960 | | int rnd_mode) |
961 | 0 | { |
962 | 0 | int e_offset; |
963 | |
|
964 | 0 | mpb_set_u64(tmp1, m); |
965 | 0 | e_offset = mul_pow(tmp1, radix1, radix_shift, f, TRUE, e); |
966 | 0 | mpb_shr_round(tmp1, -e + e_offset, rnd_mode); |
967 | 0 | } |
968 | | |
969 | | /* return round(a*2^e_offset) rounded as a float64. 'a' is modified */ |
970 | | static uint64_t round_to_d(int *pe, mpb_t *a, int e_offset, int rnd_mode) |
971 | 0 | { |
972 | 0 | int e; |
973 | 0 | uint64_t m; |
974 | |
|
975 | 0 | if (a->tab[0] == 0 && a->len == 1) { |
976 | | /* zero result */ |
977 | 0 | m = 0; |
978 | 0 | e = 0; /* don't care */ |
979 | 0 | } else { |
980 | 0 | int prec, prec1, e_min; |
981 | 0 | e = mpb_floor_log2(a) + 1 - e_offset; |
982 | 0 | prec1 = 53; |
983 | 0 | e_min = -1021; |
984 | 0 | if (e < e_min) { |
985 | | /* subnormal result or zero */ |
986 | 0 | prec = prec1 - (e_min - e); |
987 | 0 | } else { |
988 | 0 | prec = prec1; |
989 | 0 | } |
990 | 0 | mpb_shr_round(a, e + e_offset - prec, rnd_mode); |
991 | 0 | m = mpb_get_u64(a); |
992 | 0 | m <<= (53 - prec); |
993 | | /* mantissa overflow due to rounding */ |
994 | 0 | if (m >= (uint64_t)1 << 53) { |
995 | 0 | m >>= 1; |
996 | 0 | e++; |
997 | 0 | } |
998 | 0 | } |
999 | 0 | *pe = e; |
1000 | 0 | return m; |
1001 | 0 | } |
1002 | | |
1003 | | /* return (m, e) such that m*2^(e-53) = round(a * radix^f) with 2^52 |
1004 | | <= m < 2^53 or m = 0. |
1005 | | 'a' is modified. */ |
1006 | | static uint64_t mul_pow_round_to_d(int *pe, mpb_t *a, |
1007 | | int radix1, int radix_shift, int f, int rnd_mode) |
1008 | 0 | { |
1009 | 0 | int e_offset; |
1010 | |
|
1011 | 0 | e_offset = mul_pow(a, radix1, radix_shift, f, FALSE, 55); |
1012 | 0 | return round_to_d(pe, a, e_offset, rnd_mode); |
1013 | 0 | } |
1014 | | |
1015 | | #ifdef JS_DTOA_DUMP_STATS |
1016 | | static int out_len_count[17]; |
1017 | | |
1018 | | void js_dtoa_dump_stats(void) |
1019 | | { |
1020 | | int i, sum; |
1021 | | sum = 0; |
1022 | | for(i = 0; i < 17; i++) |
1023 | | sum += out_len_count[i]; |
1024 | | for(i = 0; i < 17; i++) { |
1025 | | printf("%2d %8d %5.2f%%\n", |
1026 | | i + 1, out_len_count[i], (double)out_len_count[i] / sum * 100); |
1027 | | } |
1028 | | } |
1029 | | #endif |
1030 | | |
1031 | | /* return a maximum bound of the string length. The bound depends on |
1032 | | 'd' only if format = JS_DTOA_FORMAT_FRAC or if JS_DTOA_EXP_DISABLED |
1033 | | is enabled. */ |
1034 | | int js_dtoa_max_len(double d, int radix, int n_digits, int flags) |
1035 | 0 | { |
1036 | 0 | int fmt = flags & JS_DTOA_FORMAT_MASK; |
1037 | 0 | int n, e; |
1038 | 0 | uint64_t a; |
1039 | |
|
1040 | 0 | if (fmt != JS_DTOA_FORMAT_FRAC) { |
1041 | 0 | if (fmt == JS_DTOA_FORMAT_FREE) { |
1042 | 0 | n = dtoa_max_digits_table[radix - 2]; |
1043 | 0 | } else { |
1044 | 0 | n = n_digits; |
1045 | 0 | } |
1046 | 0 | if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_DISABLED) { |
1047 | | /* no exponential */ |
1048 | 0 | a = float64_as_uint64(d); |
1049 | 0 | e = (a >> 52) & 0x7ff; |
1050 | 0 | if (e == 0x7ff) { |
1051 | | /* NaN, Infinity */ |
1052 | 0 | n = 0; |
1053 | 0 | } else { |
1054 | 0 | e -= 1023; |
1055 | | /* XXX: adjust */ |
1056 | 0 | n += 10 + abs(mul_log2_radix(e - 1, radix)); |
1057 | 0 | } |
1058 | 0 | } else { |
1059 | | /* extra: sign, 1 dot and exponent "e-1000" */ |
1060 | 0 | n += 1 + 1 + 6; |
1061 | 0 | } |
1062 | 0 | } else { |
1063 | 0 | a = float64_as_uint64(d); |
1064 | 0 | e = (a >> 52) & 0x7ff; |
1065 | 0 | if (e == 0x7ff) { |
1066 | | /* NaN, Infinity */ |
1067 | 0 | n = 0; |
1068 | 0 | } else { |
1069 | | /* high bound for the integer part */ |
1070 | 0 | e -= 1023; |
1071 | | /* x < 2^(e + 1) */ |
1072 | 0 | if (e < 0) { |
1073 | 0 | n = 1; |
1074 | 0 | } else { |
1075 | 0 | n = 2 + mul_log2_radix(e - 1, radix); |
1076 | 0 | } |
1077 | | /* sign, extra digit, 1 dot */ |
1078 | 0 | n += 1 + 1 + 1 + n_digits; |
1079 | 0 | } |
1080 | 0 | } |
1081 | 0 | return max_int(n, 9); /* also include NaN and [-]Infinity */ |
1082 | 0 | } |
1083 | | |
1084 | | #if defined(__SANITIZE_ADDRESS__) && 0 |
1085 | | static void *dtoa_malloc(uint64_t **pptr, size_t size) |
1086 | | { |
1087 | | return malloc(size); |
1088 | | } |
1089 | | static void dtoa_free(void *ptr) |
1090 | | { |
1091 | | free(ptr); |
1092 | | } |
1093 | | #else |
1094 | | static void *dtoa_malloc(uint64_t **pptr, size_t size) |
1095 | 1 | { |
1096 | 1 | void *ret; |
1097 | 1 | ret = *pptr; |
1098 | 1 | *pptr += (size + 7) / 8; |
1099 | 1 | return ret; |
1100 | 1 | } |
1101 | | |
1102 | | static void dtoa_free(void *ptr) |
1103 | 1 | { |
1104 | 1 | } |
1105 | | #endif |
1106 | | |
1107 | | /* return the length */ |
1108 | | int js_dtoa(char *buf, double d, int radix, int n_digits, int flags, |
1109 | | JSDTOATempMem *tmp_mem) |
1110 | 0 | { |
1111 | 0 | uint64_t a, m, *mptr = tmp_mem->mem; |
1112 | 0 | int e, sgn, l, E, P, i, E_max, radix1, radix_shift; |
1113 | 0 | char *q; |
1114 | 0 | mpb_t *tmp1, *mant_max; |
1115 | 0 | int fmt = flags & JS_DTOA_FORMAT_MASK; |
1116 | |
|
1117 | 0 | tmp1 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX); |
1118 | 0 | mant_max = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * MANT_LEN_MAX); |
1119 | 0 | assert((mptr - tmp_mem->mem) <= sizeof(JSDTOATempMem) / sizeof(mptr[0])); |
1120 | | |
1121 | 0 | radix_shift = ctz32(radix); |
1122 | 0 | radix1 = radix >> radix_shift; |
1123 | 0 | a = float64_as_uint64(d); |
1124 | 0 | sgn = a >> 63; |
1125 | 0 | e = (a >> 52) & 0x7ff; |
1126 | 0 | m = a & (((uint64_t)1 << 52) - 1); |
1127 | 0 | q = buf; |
1128 | 0 | if (e == 0x7ff) { |
1129 | 0 | if (m == 0) { |
1130 | 0 | if (sgn) |
1131 | 0 | *q++ = '-'; |
1132 | 0 | memcpy(q, "Infinity", 8); |
1133 | 0 | q += 8; |
1134 | 0 | } else { |
1135 | 0 | memcpy(q, "NaN", 3); |
1136 | 0 | q += 3; |
1137 | 0 | } |
1138 | 0 | goto done; |
1139 | 0 | } else if (e == 0) { |
1140 | 0 | if (m == 0) { |
1141 | 0 | tmp1->len = 1; |
1142 | 0 | tmp1->tab[0] = 0; |
1143 | 0 | E = 1; |
1144 | 0 | if (fmt == JS_DTOA_FORMAT_FREE) |
1145 | 0 | P = 1; |
1146 | 0 | else if (fmt == JS_DTOA_FORMAT_FRAC) |
1147 | 0 | P = n_digits + 1; |
1148 | 0 | else |
1149 | 0 | P = n_digits; |
1150 | | /* "-0" is displayed as "0" if JS_DTOA_MINUS_ZERO is not present */ |
1151 | 0 | if (sgn && (flags & JS_DTOA_MINUS_ZERO)) |
1152 | 0 | *q++ = '-'; |
1153 | 0 | goto output; |
1154 | 0 | } |
1155 | | /* denormal number: convert to a normal number */ |
1156 | 0 | l = clz64(m) - 11; |
1157 | 0 | e -= l - 1; |
1158 | 0 | m <<= l; |
1159 | 0 | } else { |
1160 | 0 | m |= (uint64_t)1 << 52; |
1161 | 0 | } |
1162 | 0 | if (sgn) |
1163 | 0 | *q++ = '-'; |
1164 | | /* remove the bias */ |
1165 | 0 | e -= 1022; |
1166 | | /* d = 2^(e-53)*m */ |
1167 | | // printf("m=0x%016" PRIx64 " e=%d\n", m, e); |
1168 | 0 | #ifdef USE_FAST_INT |
1169 | 0 | if (fmt == JS_DTOA_FORMAT_FREE && |
1170 | 0 | e >= 1 && e <= 53 && |
1171 | 0 | (m & (((uint64_t)1 << (53 - e)) - 1)) == 0 && |
1172 | 0 | (flags & JS_DTOA_EXP_MASK) != JS_DTOA_EXP_ENABLED) { |
1173 | 0 | m >>= 53 - e; |
1174 | | /* 'm' is never zero */ |
1175 | 0 | q += u64toa_radix(q, m, radix); |
1176 | 0 | goto done; |
1177 | 0 | } |
1178 | 0 | #endif |
1179 | | |
1180 | | /* this choice of E implies F=round(x*B^(P-E) is such as: |
1181 | | B^(P-1) <= F < 2.B^P. */ |
1182 | 0 | E = 1 + mul_log2_radix(e - 1, radix); |
1183 | | |
1184 | 0 | if (fmt == JS_DTOA_FORMAT_FREE) { |
1185 | 0 | int P_max, E0, e1, E_found, P_found; |
1186 | 0 | uint64_t m1, mant_found, mant, mant_max1; |
1187 | | /* P_max is guarranteed to work by construction */ |
1188 | 0 | P_max = dtoa_max_digits_table[radix - 2]; |
1189 | 0 | E0 = E; |
1190 | 0 | E_found = 0; |
1191 | 0 | P_found = 0; |
1192 | 0 | mant_found = 0; |
1193 | | /* find the minimum number of digits by successive tries */ |
1194 | 0 | P = P_max; /* P_max is guarateed to work */ |
1195 | 0 | for(;;) { |
1196 | | /* mant_max always fits on 64 bits */ |
1197 | 0 | mant_max1 = pow_ui(radix, P); |
1198 | | /* compute the mantissa in base B */ |
1199 | 0 | E = E0; |
1200 | 0 | for(;;) { |
1201 | | /* XXX: add inexact flag */ |
1202 | 0 | mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDN); |
1203 | 0 | mant = mpb_get_u64(tmp1); |
1204 | 0 | if (mant < mant_max1) |
1205 | 0 | break; |
1206 | 0 | E++; /* at most one iteration is possible */ |
1207 | 0 | } |
1208 | | /* remove useless trailing zero digits */ |
1209 | 0 | while ((mant % radix) == 0) { |
1210 | 0 | mant /= radix; |
1211 | 0 | P--; |
1212 | 0 | } |
1213 | | /* garanteed to work for P = P_max */ |
1214 | 0 | if (P_found == 0) |
1215 | 0 | goto prec_found; |
1216 | | /* convert back to base 2 */ |
1217 | 0 | mpb_set_u64(tmp1, mant); |
1218 | 0 | m1 = mul_pow_round_to_d(&e1, tmp1, radix1, radix_shift, E - P, JS_RNDN); |
1219 | | // printf("P=%2d: m=0x%016" PRIx64 " e=%d m1=0x%016" PRIx64 " e1=%d\n", P, m, e, m1, e1); |
1220 | | /* Note: (m, e) is never zero here, so the exponent for m1 |
1221 | | = 0 does not matter */ |
1222 | 0 | if (m1 == m && e1 == e) { |
1223 | 0 | prec_found: |
1224 | 0 | P_found = P; |
1225 | 0 | E_found = E; |
1226 | 0 | mant_found = mant; |
1227 | 0 | if (P == 1) |
1228 | 0 | break; |
1229 | 0 | P--; /* try lower exponent */ |
1230 | 0 | } else { |
1231 | 0 | break; |
1232 | 0 | } |
1233 | 0 | } |
1234 | 0 | P = P_found; |
1235 | 0 | E = E_found; |
1236 | 0 | mpb_set_u64(tmp1, mant_found); |
1237 | | #ifdef JS_DTOA_DUMP_STATS |
1238 | | if (radix == 10) { |
1239 | | out_len_count[P - 1]++; |
1240 | | } |
1241 | | #endif |
1242 | 0 | } else if (fmt == JS_DTOA_FORMAT_FRAC) { |
1243 | 0 | int len; |
1244 | |
|
1245 | 0 | assert(n_digits >= 0 && n_digits <= JS_DTOA_MAX_DIGITS); |
1246 | | /* P = max_int(E, 1) + n_digits; */ |
1247 | | /* frac is rounded using RNDNA */ |
1248 | 0 | mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, n_digits, JS_RNDNA); |
1249 | | |
1250 | | /* we add one extra digit on the left and remove it if needed |
1251 | | to avoid testing if the result is < radix^P */ |
1252 | 0 | len = output_digits(q, tmp1, radix, max_int(E + 1, 1) + n_digits, |
1253 | 0 | max_int(E + 1, 1)); |
1254 | 0 | if (q[0] == '0' && len >= 2 && q[1] != '.') { |
1255 | 0 | len--; |
1256 | 0 | memmove(q, q + 1, len); |
1257 | 0 | } |
1258 | 0 | q += len; |
1259 | 0 | goto done; |
1260 | 0 | } else { |
1261 | 0 | int pow_shift; |
1262 | 0 | assert(n_digits >= 1 && n_digits <= JS_DTOA_MAX_DIGITS); |
1263 | 0 | P = n_digits; |
1264 | | /* mant_max = radix^P */ |
1265 | 0 | mant_max->len = 1; |
1266 | 0 | mant_max->tab[0] = 1; |
1267 | 0 | pow_shift = mul_pow(mant_max, radix1, radix_shift, P, FALSE, 0); |
1268 | 0 | mpb_shr_round(mant_max, pow_shift, JS_RNDZ); |
1269 | | |
1270 | 0 | for(;;) { |
1271 | | /* fixed and frac are rounded using RNDNA */ |
1272 | 0 | mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDNA); |
1273 | 0 | if (mpb_cmp(tmp1, mant_max) < 0) |
1274 | 0 | break; |
1275 | 0 | E++; /* at most one iteration is possible */ |
1276 | 0 | } |
1277 | 0 | } |
1278 | 0 | output: |
1279 | 0 | if (fmt == JS_DTOA_FORMAT_FIXED) |
1280 | 0 | E_max = n_digits; |
1281 | 0 | else |
1282 | 0 | E_max = dtoa_max_digits_table[radix - 2] + 4; |
1283 | 0 | if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_ENABLED || |
1284 | 0 | ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_AUTO && (E <= -6 || E > E_max))) { |
1285 | 0 | q += output_digits(q, tmp1, radix, P, 1); |
1286 | 0 | E--; |
1287 | 0 | if (radix == 10) { |
1288 | 0 | *q++ = 'e'; |
1289 | 0 | } else if (radix1 == 1 && radix_shift <= 4) { |
1290 | 0 | E *= radix_shift; |
1291 | 0 | *q++ = 'p'; |
1292 | 0 | } else { |
1293 | 0 | *q++ = '@'; |
1294 | 0 | } |
1295 | 0 | if (E < 0) { |
1296 | 0 | *q++ = '-'; |
1297 | 0 | E = -E; |
1298 | 0 | } else { |
1299 | 0 | *q++ = '+'; |
1300 | 0 | } |
1301 | 0 | q += u32toa(q, E); |
1302 | 0 | } else if (E <= 0) { |
1303 | 0 | *q++ = '0'; |
1304 | 0 | *q++ = '.'; |
1305 | 0 | for(i = 0; i < -E; i++) |
1306 | 0 | *q++ = '0'; |
1307 | 0 | q += output_digits(q, tmp1, radix, P, P); |
1308 | 0 | } else { |
1309 | 0 | q += output_digits(q, tmp1, radix, P, min_int(P, E)); |
1310 | 0 | for(i = 0; i < E - P; i++) |
1311 | 0 | *q++ = '0'; |
1312 | 0 | } |
1313 | 0 | done: |
1314 | 0 | *q = '\0'; |
1315 | 0 | dtoa_free(mant_max); |
1316 | 0 | dtoa_free(tmp1); |
1317 | 0 | return q - buf; |
1318 | 0 | } |
1319 | | |
1320 | | static inline int to_digit(int c) |
1321 | 1.04M | { |
1322 | 1.04M | if (c >= '0' && c <= '9') |
1323 | 20 | return c - '0'; |
1324 | 1.04M | else if (c >= 'A' && c <= 'Z') |
1325 | 0 | return c - 'A' + 10; |
1326 | 1.04M | else if (c >= 'a' && c <= 'z') |
1327 | 1.04M | return c - 'a' + 10; |
1328 | 1 | else |
1329 | 1 | return 36; |
1330 | 1.04M | } |
1331 | | |
1332 | | /* r = r * radix_base + a. radix_base = 0 means radix_base = 2^32 */ |
1333 | | static void mpb_mul1_base(mpb_t *r, limb_t radix_base, limb_t a) |
1334 | 2 | { |
1335 | 2 | int i; |
1336 | 2 | if (r->tab[0] == 0 && r->len == 1) { |
1337 | 1 | r->tab[0] = a; |
1338 | 1 | } else { |
1339 | 1 | if (radix_base == 0) { |
1340 | 3 | for(i = r->len; i >= 0; i--) { |
1341 | 2 | r->tab[i + 1] = r->tab[i]; |
1342 | 2 | } |
1343 | 1 | r->tab[0] = a; |
1344 | 1 | } else { |
1345 | 0 | r->tab[r->len] = mp_mul1(r->tab, r->tab, r->len, |
1346 | 0 | radix_base, a); |
1347 | 0 | } |
1348 | 1 | r->len++; |
1349 | 1 | mpb_renorm(r); |
1350 | 1 | } |
1351 | 2 | } |
1352 | | |
1353 | | /* XXX: add fast path for small integers */ |
1354 | | double js_atod(const char *str, const char **pnext, int radix, int flags, |
1355 | | JSATODTempMem *tmp_mem) |
1356 | 1 | { |
1357 | 1 | uint64_t *mptr = tmp_mem->mem; |
1358 | 1 | const char *p, *p_start; |
1359 | 1 | limb_t cur_limb, radix_base, extra_digits; |
1360 | 1 | int is_neg, digit_count, limb_digit_count, digits_per_limb, sep, radix1, radix_shift; |
1361 | 1 | int radix_bits, expn, e, max_digits, expn_offset, dot_pos, sig_pos, pos; |
1362 | 1 | mpb_t *tmp0; |
1363 | 1 | double dval; |
1364 | 1 | BOOL is_bin_exp, is_zero, expn_overflow; |
1365 | 1 | uint64_t m, a; |
1366 | | |
1367 | 1 | tmp0 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX); |
1368 | 1 | assert((mptr - tmp_mem->mem) <= sizeof(JSATODTempMem) / sizeof(mptr[0])); |
1369 | | /* optional separator between digits */ |
1370 | 1 | sep = (flags & JS_ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; |
1371 | | |
1372 | 1 | p = str; |
1373 | 1 | is_neg = 0; |
1374 | 1 | if (p[0] == '+') { |
1375 | 0 | p++; |
1376 | 0 | p_start = p; |
1377 | 1 | } else if (p[0] == '-') { |
1378 | 0 | is_neg = 1; |
1379 | 0 | p++; |
1380 | 0 | p_start = p; |
1381 | 1 | } else { |
1382 | 1 | p_start = p; |
1383 | 1 | } |
1384 | | |
1385 | 1 | if (p[0] == '0') { |
1386 | 0 | if ((p[1] == 'x' || p[1] == 'X') && |
1387 | 0 | (radix == 0 || radix == 16)) { |
1388 | 0 | p += 2; |
1389 | 0 | radix = 16; |
1390 | 0 | } else if ((p[1] == 'o' || p[1] == 'O') && |
1391 | 0 | radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) { |
1392 | 0 | p += 2; |
1393 | 0 | radix = 8; |
1394 | 0 | } else if ((p[1] == 'b' || p[1] == 'B') && |
1395 | 0 | radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) { |
1396 | 0 | p += 2; |
1397 | 0 | radix = 2; |
1398 | 0 | } else if ((p[1] >= '0' && p[1] <= '9') && |
1399 | 0 | radix == 0 && (flags & JS_ATOD_ACCEPT_LEGACY_OCTAL)) { |
1400 | 0 | int i; |
1401 | 0 | sep = 256; |
1402 | 0 | for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++) |
1403 | 0 | continue; |
1404 | 0 | if (p[i] == '8' || p[i] == '9') |
1405 | 0 | goto no_prefix; |
1406 | 0 | p += 1; |
1407 | 0 | radix = 8; |
1408 | 0 | } else { |
1409 | 0 | goto no_prefix; |
1410 | 0 | } |
1411 | | /* there must be a digit after the prefix */ |
1412 | 0 | if (to_digit((uint8_t)*p) >= radix) |
1413 | 0 | goto fail; |
1414 | 0 | no_prefix: ; |
1415 | 1 | } else { |
1416 | 1 | if (!(flags & JS_ATOD_INT_ONLY) && strstart(p, "Infinity", &p)) |
1417 | 0 | goto overflow; |
1418 | 1 | } |
1419 | 1 | if (radix == 0) |
1420 | 0 | radix = 10; |
1421 | | |
1422 | 1 | cur_limb = 0; |
1423 | 1 | expn_offset = 0; |
1424 | 1 | digit_count = 0; |
1425 | 1 | limb_digit_count = 0; |
1426 | 1 | max_digits = atod_max_digits_table[radix - 2]; |
1427 | 1 | digits_per_limb = digits_per_limb_table[radix - 2]; |
1428 | 1 | radix_base = radix_base_table[radix - 2]; |
1429 | 1 | radix_shift = ctz32(radix); |
1430 | 1 | radix1 = radix >> radix_shift; |
1431 | 1 | if (radix1 == 1) { |
1432 | | /* radix = 2^radix_bits */ |
1433 | 1 | radix_bits = radix_shift; |
1434 | 1 | } else { |
1435 | 0 | radix_bits = 0; |
1436 | 0 | } |
1437 | 1 | tmp0->len = 1; |
1438 | 1 | tmp0->tab[0] = 0; |
1439 | 1 | extra_digits = 0; |
1440 | 1 | pos = 0; |
1441 | 1 | dot_pos = -1; |
1442 | | /* skip leading zeros */ |
1443 | 1 | for(;;) { |
1444 | 1 | if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) && |
1445 | 1 | !(flags & JS_ATOD_INT_ONLY)) { |
1446 | 0 | if (*p == sep) |
1447 | 0 | goto fail; |
1448 | 0 | if (dot_pos >= 0) |
1449 | 0 | break; |
1450 | 0 | dot_pos = pos; |
1451 | 0 | p++; |
1452 | 0 | } |
1453 | 1 | if (*p == sep && p > p_start && p[1] == '0') |
1454 | 0 | p++; |
1455 | 1 | if (*p != '0') |
1456 | 1 | break; |
1457 | 0 | p++; |
1458 | 0 | pos++; |
1459 | 0 | } |
1460 | | |
1461 | 1 | sig_pos = pos; |
1462 | 1.04M | for(;;) { |
1463 | 1.04M | limb_t c; |
1464 | 1.04M | if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) && |
1465 | 1.04M | !(flags & JS_ATOD_INT_ONLY)) { |
1466 | 0 | if (*p == sep) |
1467 | 0 | goto fail; |
1468 | 0 | if (dot_pos >= 0) |
1469 | 0 | break; |
1470 | 0 | dot_pos = pos; |
1471 | 0 | p++; |
1472 | 0 | } |
1473 | 1.04M | if (*p == sep && p > p_start && to_digit(p[1]) < radix) |
1474 | 0 | p++; |
1475 | 1.04M | c = to_digit(*p); |
1476 | 1.04M | if (c >= radix) |
1477 | 1 | break; |
1478 | 1.04M | p++; |
1479 | 1.04M | pos++; |
1480 | 1.04M | if (digit_count < max_digits) { |
1481 | | /* XXX: could be faster when radix_bits != 0 */ |
1482 | 16 | cur_limb = cur_limb * radix + c; |
1483 | 16 | limb_digit_count++; |
1484 | 16 | if (limb_digit_count == digits_per_limb) { |
1485 | 2 | mpb_mul1_base(tmp0, radix_base, cur_limb); |
1486 | 2 | cur_limb = 0; |
1487 | 2 | limb_digit_count = 0; |
1488 | 2 | } |
1489 | 16 | digit_count++; |
1490 | 1.04M | } else { |
1491 | 1.04M | extra_digits |= c; |
1492 | 1.04M | } |
1493 | 1.04M | } |
1494 | 1 | if (limb_digit_count != 0) { |
1495 | 0 | mpb_mul1_base(tmp0, pow_ui(radix, limb_digit_count), cur_limb); |
1496 | 0 | } |
1497 | 1 | if (digit_count == 0) { |
1498 | 0 | is_zero = TRUE; |
1499 | 0 | expn_offset = 0; |
1500 | 1 | } else { |
1501 | 1 | is_zero = FALSE; |
1502 | 1 | if (dot_pos < 0) |
1503 | 1 | dot_pos = pos; |
1504 | 1 | expn_offset = sig_pos + digit_count - dot_pos; |
1505 | 1 | } |
1506 | | |
1507 | | /* Use the extra digits for rounding if the base is a power of |
1508 | | two. Otherwise they are just truncated. */ |
1509 | 1 | if (radix_bits != 0 && extra_digits != 0) { |
1510 | 1 | tmp0->tab[0] |= 1; |
1511 | 1 | } |
1512 | | |
1513 | | /* parse the exponent, if any */ |
1514 | 1 | expn = 0; |
1515 | 1 | expn_overflow = FALSE; |
1516 | 1 | is_bin_exp = FALSE; |
1517 | 1 | if (!(flags & JS_ATOD_INT_ONLY) && |
1518 | 1 | ((radix == 10 && (*p == 'e' || *p == 'E')) || |
1519 | 0 | (radix != 10 && (*p == '@' || |
1520 | 0 | (radix_bits >= 1 && radix_bits <= 4 && (*p == 'p' || *p == 'P'))))) && |
1521 | 1 | p > p_start) { |
1522 | 0 | BOOL exp_is_neg; |
1523 | 0 | int c; |
1524 | 0 | is_bin_exp = (*p == 'p' || *p == 'P'); |
1525 | 0 | p++; |
1526 | 0 | exp_is_neg = 0; |
1527 | 0 | if (*p == '+') { |
1528 | 0 | p++; |
1529 | 0 | } else if (*p == '-') { |
1530 | 0 | exp_is_neg = 1; |
1531 | 0 | p++; |
1532 | 0 | } |
1533 | 0 | c = to_digit(*p); |
1534 | 0 | if (c >= 10) |
1535 | 0 | goto fail; /* XXX: could stop before the exponent part */ |
1536 | 0 | expn = c; |
1537 | 0 | p++; |
1538 | 0 | for(;;) { |
1539 | 0 | if (*p == sep && to_digit(p[1]) < 10) |
1540 | 0 | p++; |
1541 | 0 | c = to_digit(*p); |
1542 | 0 | if (c >= 10) |
1543 | 0 | break; |
1544 | 0 | if (!expn_overflow) { |
1545 | 0 | if (unlikely(expn > ((INT32_MAX - 2 - 9) / 10))) { |
1546 | 0 | expn_overflow = TRUE; |
1547 | 0 | } else { |
1548 | 0 | expn = expn * 10 + c; |
1549 | 0 | } |
1550 | 0 | } |
1551 | 0 | p++; |
1552 | 0 | } |
1553 | 0 | if (exp_is_neg) |
1554 | 0 | expn = -expn; |
1555 | | /* if zero result, the exponent can be arbitrarily large */ |
1556 | 0 | if (!is_zero && expn_overflow) { |
1557 | 0 | if (exp_is_neg) |
1558 | 0 | a = 0; |
1559 | 0 | else |
1560 | 0 | a = (uint64_t)0x7ff << 52; /* infinity */ |
1561 | 0 | goto done; |
1562 | 0 | } |
1563 | 0 | } |
1564 | | |
1565 | 1 | if (p == p_start) |
1566 | 0 | goto fail; |
1567 | | |
1568 | 1 | if (is_zero) { |
1569 | 0 | a = 0; |
1570 | 1 | } else { |
1571 | 1 | int expn1; |
1572 | 1 | if (radix_bits != 0) { |
1573 | 1 | if (!is_bin_exp) |
1574 | 1 | expn *= radix_bits; |
1575 | 1 | expn -= expn_offset * radix_bits; |
1576 | 1 | expn1 = expn + digit_count * radix_bits; |
1577 | 1 | if (expn1 >= 1024 + radix_bits) |
1578 | 1 | goto overflow; |
1579 | 0 | else if (expn1 <= -1075) |
1580 | 0 | goto underflow; |
1581 | 0 | m = round_to_d(&e, tmp0, -expn, JS_RNDN); |
1582 | 0 | } else { |
1583 | 0 | expn -= expn_offset; |
1584 | 0 | expn1 = expn + digit_count; |
1585 | 0 | if (expn1 >= max_exponent[radix - 2] + 1) |
1586 | 0 | goto overflow; |
1587 | 0 | else if (expn1 <= min_exponent[radix - 2]) |
1588 | 0 | goto underflow; |
1589 | 0 | m = mul_pow_round_to_d(&e, tmp0, radix1, radix_shift, expn, JS_RNDN); |
1590 | 0 | } |
1591 | 0 | if (m == 0) { |
1592 | 0 | underflow: |
1593 | 0 | a = 0; |
1594 | 0 | } else if (e > 1024) { |
1595 | 1 | overflow: |
1596 | | /* overflow */ |
1597 | 1 | a = (uint64_t)0x7ff << 52; |
1598 | 1 | } else if (e < -1073) { |
1599 | | /* underflow */ |
1600 | | /* XXX: check rounding */ |
1601 | 0 | a = 0; |
1602 | 0 | } else if (e < -1021) { |
1603 | | /* subnormal */ |
1604 | 0 | a = m >> (-e - 1021); |
1605 | 0 | } else { |
1606 | 0 | a = ((uint64_t)(e + 1022) << 52) | (m & (((uint64_t)1 << 52) - 1)); |
1607 | 0 | } |
1608 | 0 | } |
1609 | 1 | done: |
1610 | 1 | a |= (uint64_t)is_neg << 63; |
1611 | 1 | dval = uint64_as_float64(a); |
1612 | 1 | done1: |
1613 | 1 | if (pnext) |
1614 | 0 | *pnext = p; |
1615 | 1 | dtoa_free(tmp0); |
1616 | 1 | return dval; |
1617 | 0 | fail: |
1618 | 0 | dval = NAN; |
1619 | 0 | goto done1; |
1620 | 1 | } |