refactor headers, especially alltypes.h, and improve C++ ABI compat
[musl] / src / internal / floatscan.c
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <math.h>
4 #include <float.h>
5 #include <limits.h>
6 #include <errno.h>
7 #include <ctype.h>
8
9 #include "shgetc.h"
10 #include "floatscan.h"
11
12 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
13
14 #define LD_B1B_DIG 2
15 #define LD_B1B_MAX 9007199, 254740991
16 #define KMAX 128
17
18 #else /* LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 */
19
20 #define LD_B1B_DIG 3
21 #define LD_B1B_MAX 18, 446744073, 709551615
22 #define KMAX 2048
23
24 #endif
25
26 #define MASK (KMAX-1)
27
28 #define CONCAT2(x,y) x ## y
29 #define CONCAT(x,y) CONCAT2(x,y)
30
31 static long long scanexp(FILE *f, int pok)
32 {
33         int c;
34         int x;
35         long long y;
36         int neg = 0;
37         
38         c = shgetc(f);
39         if (c=='+' || c=='-') {
40                 neg = (c=='-');
41                 c = shgetc(f);
42                 if (c-'0'>=10U && pok) shunget(f);
43         }
44         if (c-'0'>=10U) {
45                 shunget(f);
46                 return LLONG_MIN;
47         }
48         for (x=0; c-'0'<10U && x<INT_MAX/10; c = shgetc(f))
49                 x = 10*x + c-'0';
50         for (y=x; c-'0'<10U && y<LLONG_MAX/100; c = shgetc(f))
51                 y = 10*y + c-'0';
52         for (; c-'0'<10U; c = shgetc(f));
53         shunget(f);
54         return neg ? -y : y;
55 }
56
57
58 static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int pok)
59 {
60         uint32_t x[KMAX];
61         static const uint32_t th[] = { LD_B1B_MAX };
62         int i, j, k, a, z;
63         long long lrp=0, dc=0;
64         long long e10=0;
65         int lnz = 0;
66         int gotdig = 0, gotrad = 0;
67         int rp;
68         int e2;
69         int emax = -emin-bits+3;
70         int denormal = 0;
71         long double y;
72         long double frac=0;
73         long double bias=0;
74         static const int p10s[] = { 10, 100, 1000, 10000,
75                 100000, 1000000, 10000000, 100000000 };
76
77         j=0;
78         k=0;
79
80         /* Don't let leading zeros consume buffer space */
81         for (; c=='0'; c = shgetc(f)) gotdig=1;
82         if (c=='.') {
83                 gotrad = 1;
84                 for (c = shgetc(f); c=='0'; c = shgetc(f)) gotdig=1, lrp--;
85         }
86
87         x[0] = 0;
88         for (; c-'0'<10U || c=='.'; c = shgetc(f)) {
89                 if (c == '.') {
90                         if (gotrad) break;
91                         gotrad = 1;
92                         lrp = dc;
93                 } else if (k < KMAX-3) {
94                         dc++;
95                         if (c!='0') lnz = dc;
96                         if (j) x[k] = x[k]*10 + c-'0';
97                         else x[k] = c-'0';
98                         if (++j==9) {
99                                 k++;
100                                 j=0;
101                         }
102                         gotdig=1;
103                 } else {
104                         dc++;
105                         if (c!='0') x[KMAX-4] |= 1;
106                 }
107         }
108         if (!gotrad) lrp=dc;
109
110         if (gotdig && (c|32)=='e') {
111                 e10 = scanexp(f, pok);
112                 if (e10 == LLONG_MIN) {
113                         if (pok) {
114                                 shunget(f);
115                         } else {
116                                 shlim(f, 0);
117                                 return 0;
118                         }
119                         e10 = 0;
120                 }
121                 lrp += e10;
122         } else if (c>=0) {
123                 shunget(f);
124         }
125         if (!gotdig) {
126                 errno = EINVAL;
127                 shlim(f, 0);
128                 return 0;
129         }
130
131         /* Handle zero specially to avoid nasty special cases later */
132         if (!x[0]) return sign * 0.0;
133
134         /* Optimize small integers (w/no exponent) and over/under-flow */
135         if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0))
136                 return sign * (long double)x[0];
137         if (lrp > -emin/2) {
138                 errno = ERANGE;
139                 return sign * LDBL_MAX * LDBL_MAX;
140         }
141         if (lrp < emin-2*LDBL_MANT_DIG) {
142                 errno = ERANGE;
143                 return sign * LDBL_MIN * LDBL_MIN;
144         }
145
146         /* Align incomplete final B1B digit */
147         if (j) {
148                 for (; j<9; j++) x[k]*=10;
149                 k++;
150                 j=0;
151         }
152
153         a = 0;
154         z = k;
155         e2 = 0;
156         rp = lrp;
157
158         /* Optimize small to mid-size integers (even in exp. notation) */
159         if (lnz<9 && lnz<=rp && rp < 18) {
160                 if (rp == 9) return sign * (long double)x[0];
161                 if (rp < 9) return sign * (long double)x[0] / p10s[8-rp];
162                 int bitlim = bits-3*(int)(rp-9);
163                 if (bitlim>30 || x[0]>>bitlim==0)
164                         return sign * (long double)x[0] * p10s[rp-10];
165         }
166
167         /* Align radix point to B1B digit boundary */
168         if (rp % 9) {
169                 int rpm9 = rp>=0 ? rp%9 : rp%9+9;
170                 int p10 = p10s[8-rpm9];
171                 uint32_t carry = 0;
172                 for (k=a; k!=z; k++) {
173                         uint32_t tmp = x[k] % p10;
174                         x[k] = x[k]/p10 + carry;
175                         carry = 1000000000/p10 * tmp;
176                         if (k==a && !x[k]) {
177                                 a = (a+1 & MASK);
178                                 rp -= 9;
179                         }
180                 }
181                 if (carry) x[z++] = carry;
182                 rp += 9-rpm9;
183         }
184
185         /* Upscale until desired number of bits are left of radix point */
186         while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a]<th[0])) {
187                 uint32_t carry = 0;
188                 e2 -= 29;
189                 for (k=(z-1 & MASK); ; k=(k-1 & MASK)) {
190                         uint64_t tmp = ((uint64_t)x[k] << 29) + carry;
191                         if (tmp > 1000000000) {
192                                 carry = tmp / 1000000000;
193                                 x[k] = tmp % 1000000000;
194                         } else {
195                                 carry = 0;
196                                 x[k] = tmp;
197                         }
198                         if (k==(z-1 & MASK) && k!=a && !x[k]) z = k;
199                         if (k==a) break;
200                 }
201                 if (carry) {
202                         rp += 9;
203                         a = (a-1 & MASK);
204                         if (a == z) {
205                                 z = (z-1 & MASK);
206                                 x[z-1 & MASK] |= x[z];
207                         }
208                         x[a] = carry;
209                 }
210         }
211
212         /* Downscale until exactly number of bits are left of radix point */
213         for (;;) {
214                 uint32_t carry = 0;
215                 int sh = 1;
216                 for (i=0; i<LD_B1B_DIG; i++) {
217                         k = (a+i & MASK);
218                         if (k == z || x[k] < th[i]) {
219                                 i=LD_B1B_DIG;
220                                 break;
221                         }
222                         if (x[a+i & MASK] > th[i]) break;
223                 }
224                 if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break;
225                 /* FIXME: find a way to compute optimal sh */
226                 if (rp > 9+9*LD_B1B_DIG) sh = 9;
227                 e2 += sh;
228                 for (k=a; k!=z; k=(k+1 & MASK)) {
229                         uint32_t tmp = x[k] & (1<<sh)-1;
230                         x[k] = (x[k]>>sh) + carry;
231                         carry = (1000000000>>sh) * tmp;
232                         if (k==a && !x[k]) {
233                                 a = (a+1 & MASK);
234                                 i--;
235                                 rp -= 9;
236                         }
237                 }
238                 if (carry) {
239                         if ((z+1 & MASK) != a) {
240                                 x[z] = carry;
241                                 z = (z+1 & MASK);
242                         } else x[z-1 & MASK] |= 1;
243                 }
244         }
245
246         /* Assemble desired bits into floating point variable */
247         for (y=i=0; i<LD_B1B_DIG; i++) {
248                 if ((a+i & MASK)==z) x[(z=(z+1 & MASK))-1] = 0;
249                 y = 1000000000.0L * y + x[a+i & MASK];
250         }
251
252         y *= sign;
253
254         /* Limit precision for denormal results */
255         if (bits > LDBL_MANT_DIG+e2-emin) {
256                 bits = LDBL_MANT_DIG+e2-emin;
257                 if (bits<0) bits=0;
258                 denormal = 1;
259         }
260
261         /* Calculate bias term to force rounding, move out lower bits */
262         if (bits < LDBL_MANT_DIG) {
263                 bias = copysignl(scalbn(1, 2*LDBL_MANT_DIG-bits-1), y);
264                 frac = fmodl(y, scalbn(1, LDBL_MANT_DIG-bits));
265                 y -= frac;
266                 y += bias;
267         }
268
269         /* Process tail of decimal input so it can affect rounding */
270         if ((a+i & MASK) != z) {
271                 uint32_t t = x[a+i & MASK];
272                 if (t < 500000000 && (t || (a+i+1 & MASK) != z))
273                         frac += 0.25*sign;
274                 else if (t > 500000000)
275                         frac += 0.75*sign;
276                 else if (t == 500000000) {
277                         if ((a+i+1 & MASK) == z)
278                                 frac += 0.5*sign;
279                         else
280                                 frac += 0.75*sign;
281                 }
282                 if (LDBL_MANT_DIG-bits >= 2 && !fmodl(frac, 1))
283                         frac++;
284         }
285
286         y += frac;
287         y -= bias;
288
289         if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) {
290                 if (fabs(y) >= CONCAT(0x1p, LDBL_MANT_DIG)) {
291                         if (denormal && bits==LDBL_MANT_DIG+e2-emin)
292                                 denormal = 0;
293                         y *= 0.5;
294                         e2++;
295                 }
296                 if (e2+LDBL_MANT_DIG>emax || (denormal && frac))
297                         errno = ERANGE;
298         }
299
300         return scalbnl(y, e2);
301 }
302
303 static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok)
304 {
305         uint32_t x = 0;
306         long double y = 0;
307         long double scale = 1;
308         long double bias = 0;
309         int gottail = 0, gotrad = 0, gotdig = 0;
310         long long rp = 0;
311         long long dc = 0;
312         long long e2 = 0;
313         int d;
314         int c;
315
316         c = shgetc(f);
317
318         /* Skip leading zeros */
319         for (; c=='0'; c = shgetc(f)) gotdig = 1;
320
321         if (c=='.') {
322                 gotrad = 1;
323                 c = shgetc(f);
324                 /* Count zeros after the radix point before significand */
325                 for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1;
326         }
327
328         for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) {
329                 if (c=='.') {
330                         if (gotrad) break;
331                         rp = dc;
332                         gotrad = 1;
333                 } else {
334                         gotdig = 1;
335                         if (c > '9') d = (c|32)+10-'a';
336                         else d = c-'0';
337                         if (dc<8) {
338                                 x = x*16 + d;
339                         } else if (dc < LDBL_MANT_DIG/4+1) {
340                                 y += d*(scale/=16);
341                         } else if (d && !gottail) {
342                                 y += 0.5*scale;
343                                 gottail = 1;
344                         }
345                         dc++;
346                 }
347         }
348         if (!gotdig) {
349                 shunget(f);
350                 if (pok) {
351                         shunget(f);
352                         if (gotrad) shunget(f);
353                 } else {
354                         shlim(f, 0);
355                 }
356                 return sign * 0.0;
357         }
358         if (!gotrad) rp = dc;
359         while (dc<8) x *= 16, dc++;
360         if ((c|32)=='p') {
361                 e2 = scanexp(f, pok);
362                 if (e2 == LLONG_MIN) {
363                         if (pok) {
364                                 shunget(f);
365                         } else {
366                                 shlim(f, 0);
367                                 return 0;
368                         }
369                         e2 = 0;
370                 }
371         } else {
372                 shunget(f);
373         }
374         e2 += 4*rp - 32;
375
376         if (!x) return sign * 0.0;
377         if (e2 > -emin) {
378                 errno = ERANGE;
379                 return sign * LDBL_MAX * LDBL_MAX;
380         }
381         if (e2 < emin-2*LDBL_MANT_DIG) {
382                 errno = ERANGE;
383                 return sign * LDBL_MIN * LDBL_MIN;
384         }
385
386         while (x < 0x80000000) {
387                 if (y>=0.5) {
388                         x += x + 1;
389                         y += y - 1;
390                 } else {
391                         x += x;
392                         y += y;
393                 }
394                 e2--;
395         }
396
397         if (bits > 32+e2-emin) {
398                 bits = 32+e2-emin;
399                 if (bits<0) bits=0;
400         }
401
402         if (bits < LDBL_MANT_DIG)
403                 bias = copysignl(scalbn(1, 32+LDBL_MANT_DIG-bits-1), sign);
404
405         if (bits<32 && y && !(x&1)) x++, y=0;
406
407         y = bias + sign*(long double)x + sign*y;
408         y -= bias;
409
410         if (!y) errno = ERANGE;
411
412         return scalbnl(y, e2);
413 }
414
415 long double __floatscan(FILE *f, int prec, int pok)
416 {
417         int sign = 1;
418         size_t i;
419         int bits;
420         int emin;
421         int c;
422
423         switch (prec) {
424         case 0:
425                 bits = FLT_MANT_DIG;
426                 emin = FLT_MIN_EXP-bits;
427                 break;
428         case 1:
429                 bits = DBL_MANT_DIG;
430                 emin = DBL_MIN_EXP-bits;
431                 break;
432         case 2:
433                 bits = LDBL_MANT_DIG;
434                 emin = LDBL_MIN_EXP-bits;
435                 break;
436         default:
437                 return 0;
438         }
439
440         while (isspace((c=shgetc(f))));
441
442         if (c=='+' || c=='-') {
443                 sign -= 2*(c=='-');
444                 c = shgetc(f);
445         }
446
447         for (i=0; i<8 && (c|32)=="infinity"[i]; i++)
448                 if (i<7) c = shgetc(f);
449         if (i==3 || i==8 || (i>3 && pok)) {
450                 if (i!=8) {
451                         shunget(f);
452                         if (pok) for (; i>3; i--) shunget(f);
453                 }
454                 return sign * INFINITY;
455         }
456         if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++)
457                 if (i<2) c = shgetc(f);
458         if (i==3) {
459                 if (shgetc(f) != '(') {
460                         shunget(f);
461                         return NAN;
462                 }
463                 for (i=1; ; i++) {
464                         c = shgetc(f);
465                         if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_')
466                                 continue;
467                         if (c==')') return NAN;
468                         shunget(f);
469                         if (!pok) {
470                                 errno = EINVAL;
471                                 shlim(f, 0);
472                                 return 0;
473                         }
474                         while (i--) shunget(f);
475                         return NAN;
476                 }
477                 return NAN;
478         }
479
480         if (i) {
481                 shunget(f);
482                 errno = EINVAL;
483                 shlim(f, 0);
484                 return 0;
485         }
486
487         if (c=='0') {
488                 c = shgetc(f);
489                 if ((c|32) == 'x')
490                         return hexfloat(f, bits, emin, sign, pok);
491                 shunget(f);
492                 c = '0';
493         }
494
495         return decfloat(f, c, bits, emin, sign, pok);
496 }