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