]>
git.proxmox.com Git - wasi-libc.git/blob - libc-top-half/musl/src/internal/floatscan.c
8 #ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
10 #include "printscan.h"
14 #include "floatscan.h"
16 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
19 #define LD_B1B_MAX 9007199, 254740991
22 #elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
25 #define LD_B1B_MAX 18, 446744073, 709551615
28 #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
31 #define LD_B1B_MAX 10384593, 717069655, 257060992, 658440191
35 #error Unsupported long double representation
40 #define CONCAT2(x,y) x ## y
41 #define CONCAT(x,y) CONCAT2(x,y)
43 static long long scanexp(FILE *f
, int pok
)
51 if (c
=='+' || c
=='-') {
54 if (c
-'0'>=10U && pok
) shunget(f
);
60 for (x
=0; c
-'0'<10U && x
<INT_MAX
/10; c
= shgetc(f
))
62 for (y
=x
; c
-'0'<10U && y
<LLONG_MAX
/100; c
= shgetc(f
))
64 for (; c
-'0'<10U; c
= shgetc(f
));
70 #if defined(__wasilibc_printscan_no_long_double)
71 static long_double
decfloat(FILE *f
, int c
, int bits
, int emin
, int sign
, int pok
)
73 static long double decfloat(FILE *f
, int c
, int bits
, int emin
, int sign
, int pok
)
77 static const uint32_t th
[] = { LD_B1B_MAX
};
79 long long lrp
=0, dc
=0;
82 int gotdig
= 0, gotrad
= 0;
85 int emax
= -emin
-bits
+3;
87 #if defined(__wasilibc_printscan_no_long_double)
96 static const int p10s
[] = { 10, 100, 1000, 10000,
97 100000, 1000000, 10000000, 100000000 };
102 /* Don't let leading zeros consume buffer space */
103 for (; c
=='0'; c
= shgetc(f
)) gotdig
=1;
106 for (c
= shgetc(f
); c
=='0'; c
= shgetc(f
)) gotdig
=1, lrp
--;
110 for (; c
-'0'<10U || c
=='.'; c
= shgetc(f
)) {
115 } else if (k
< KMAX
-3) {
117 if (c
!='0') lnz
= dc
;
118 if (j
) x
[k
] = x
[k
]*10 + c
-'0';
135 if (gotdig
&& (c
|32)=='e') {
136 e10
= scanexp(f
, pok
);
137 if (e10
== LLONG_MIN
) {
156 /* Handle zero specially to avoid nasty special cases later */
157 if (!x
[0]) return sign
* 0.0;
159 /* Optimize small integers (w/no exponent) and over/under-flow */
160 if (lrp
==dc
&& dc
<10 && (bits
>30 || x
[0]>>bits
==0))
161 #if defined(__wasilibc_printscan_no_long_double)
162 return sign
* (long_double
)x
[0];
164 return sign
* (long double)x
[0];
168 return sign
* LDBL_MAX
* LDBL_MAX
;
170 if (lrp
< emin
-2*LDBL_MANT_DIG
) {
172 return sign
* LDBL_MIN
* LDBL_MIN
;
175 /* Align incomplete final B1B digit */
177 for (; j
<9; j
++) x
[k
]*=10;
187 /* Optimize small to mid-size integers (even in exp. notation) */
188 if (lnz
<9 && lnz
<=rp
&& rp
< 18) {
189 #if defined(__wasilibc_printscan_no_long_double)
190 if (rp
== 9) return sign
* (long_double
)x
[0];
191 if (rp
< 9) return sign
* (long_double
)x
[0] / p10s
[8-rp
];
193 if (rp
== 9) return sign
* (long double)x
[0];
194 if (rp
< 9) return sign
* (long double)x
[0] / p10s
[8-rp
];
196 int bitlim
= bits
-3*(int)(rp
-9);
197 if (bitlim
>30 || x
[0]>>bitlim
==0)
198 #if defined(__wasilibc_printscan_no_long_double)
199 return sign
* (long_double
)x
[0] * p10s
[rp
-10];
201 return sign
* (long double)x
[0] * p10s
[rp
-10];
205 /* Drop trailing zeros */
206 for (; !x
[z
-1]; z
--);
208 /* Align radix point to B1B digit boundary */
210 int rpm9
= rp
>=0 ? rp
%9 : rp
%9+9;
211 int p10
= p10s
[8-rpm9
];
213 for (k
=a
; k
!=z
; k
++) {
214 uint32_t tmp
= x
[k
] % p10
;
215 x
[k
] = x
[k
]/p10
+ carry
;
216 carry
= 1000000000/p10
* tmp
;
222 if (carry
) x
[z
++] = carry
;
226 /* Upscale until desired number of bits are left of radix point */
227 while (rp
< 9*LD_B1B_DIG
|| (rp
== 9*LD_B1B_DIG
&& x
[a
]<th
[0])) {
230 for (k
=(z
-1 & MASK
); ; k
=(k
-1 & MASK
)) {
231 uint64_t tmp
= ((uint64_t)x
[k
] << 29) + carry
;
232 if (tmp
> 1000000000) {
233 carry
= tmp
/ 1000000000;
234 x
[k
] = tmp
% 1000000000;
239 if (k
==(z
-1 & MASK
) && k
!=a
&& !x
[k
]) z
= k
;
247 x
[z
-1 & MASK
] |= x
[z
];
253 /* Downscale until exactly number of bits are left of radix point */
257 for (i
=0; i
<LD_B1B_DIG
; i
++) {
259 if (k
== z
|| x
[k
] < th
[i
]) {
263 if (x
[a
+i
& MASK
] > th
[i
]) break;
265 if (i
==LD_B1B_DIG
&& rp
==9*LD_B1B_DIG
) break;
266 /* FIXME: find a way to compute optimal sh */
267 if (rp
> 9+9*LD_B1B_DIG
) sh
= 9;
269 for (k
=a
; k
!=z
; k
=(k
+1 & MASK
)) {
270 uint32_t tmp
= x
[k
] & (1<<sh
)-1;
271 x
[k
] = (x
[k
]>>sh
) + carry
;
272 carry
= (1000000000>>sh
) * tmp
;
280 if ((z
+1 & MASK
) != a
) {
283 } else x
[z
-1 & MASK
] |= 1;
287 /* Assemble desired bits into floating point variable */
288 for (y
=i
=0; i
<LD_B1B_DIG
; i
++) {
289 if ((a
+i
& MASK
)==z
) x
[(z
=(z
+1 & MASK
))-1] = 0;
290 #if defined(__wasilibc_printscan_no_long_double)
291 y
= 1000000000.0 * y
+ x
[a
+i
& MASK
];
293 y
= 1000000000.0L * y
+ x
[a
+i
& MASK
];
299 /* Limit precision for denormal results */
300 if (bits
> LDBL_MANT_DIG
+e2
-emin
) {
301 bits
= LDBL_MANT_DIG
+e2
-emin
;
306 /* Calculate bias term to force rounding, move out lower bits */
307 if (bits
< LDBL_MANT_DIG
) {
308 bias
= copysignl(scalbn(1, 2*LDBL_MANT_DIG
-bits
-1), y
);
309 frac
= fmodl(y
, scalbn(1, LDBL_MANT_DIG
-bits
));
314 /* Process tail of decimal input so it can affect rounding */
315 if ((a
+i
& MASK
) != z
) {
316 uint32_t t
= x
[a
+i
& MASK
];
317 if (t
< 500000000 && (t
|| (a
+i
+1 & MASK
) != z
))
319 else if (t
> 500000000)
321 else if (t
== 500000000) {
322 if ((a
+i
+1 & MASK
) == z
)
327 if (LDBL_MANT_DIG
-bits
>= 2 && !fmodl(frac
, 1))
334 if ((e2
+LDBL_MANT_DIG
& INT_MAX
) > emax
-5) {
335 if (fabs(y
) >= CONCAT(0x1p
, LDBL_MANT_DIG
)) {
336 if (denormal
&& bits
==LDBL_MANT_DIG
+e2
-emin
)
341 if (e2
+LDBL_MANT_DIG
>emax
|| (denormal
&& frac
))
345 return scalbnl(y
, e2
);
348 #if defined(__wasilibc_printscan_no_long_double)
349 static long_double
hexfloat(FILE *f
, int bits
, int emin
, int sign
, int pok
)
351 static long double hexfloat(FILE *f
, int bits
, int emin
, int sign
, int pok
)
355 #if defined(__wasilibc_printscan_no_long_double)
357 long_double scale
= 1;
358 long_double bias
= 0;
361 long double scale
= 1;
362 long double bias
= 0;
364 int gottail
= 0, gotrad
= 0, gotdig
= 0;
373 /* Skip leading zeros */
374 for (; c
=='0'; c
= shgetc(f
)) gotdig
= 1;
379 /* Count zeros after the radix point before significand */
380 for (rp
=0; c
=='0'; c
= shgetc(f
), rp
--) gotdig
= 1;
383 for (; c
-'0'<10U || (c
|32)-'a'<6U || c
=='.'; c
= shgetc(f
)) {
390 if (c
> '9') d
= (c
|32)+10-'a';
394 } else if (dc
< LDBL_MANT_DIG
/4+1) {
396 } else if (d
&& !gottail
) {
407 if (gotrad
) shunget(f
);
413 if (!gotrad
) rp
= dc
;
414 while (dc
<8) x
*= 16, dc
++;
416 e2
= scanexp(f
, pok
);
417 if (e2
== LLONG_MIN
) {
431 if (!x
) return sign
* 0.0;
434 return sign
* LDBL_MAX
* LDBL_MAX
;
436 if (e2
< emin
-2*LDBL_MANT_DIG
) {
438 return sign
* LDBL_MIN
* LDBL_MIN
;
441 while (x
< 0x80000000) {
452 if (bits
> 32+e2
-emin
) {
457 if (bits
< LDBL_MANT_DIG
)
458 bias
= copysignl(scalbn(1, 32+LDBL_MANT_DIG
-bits
-1), sign
);
460 if (bits
<32 && y
&& !(x
&1)) x
++, y
=0;
462 #if defined(__wasilibc_printscan_no_long_double)
463 y
= bias
+ sign
*(long_double
)x
+ sign
*y
;
465 y
= bias
+ sign
*(long double)x
+ sign
*y
;
469 if (!y
) errno
= ERANGE
;
471 return scalbnl(y
, e2
);
474 #if defined(__wasilibc_printscan_no_long_double)
475 long_double
__floatscan(FILE *f
, int prec
, int pok
)
477 long double __floatscan(FILE *f
, int prec
, int pok
)
489 emin
= FLT_MIN_EXP
-bits
;
493 emin
= DBL_MIN_EXP
-bits
;
496 bits
= LDBL_MANT_DIG
;
497 emin
= LDBL_MIN_EXP
-bits
;
503 while (isspace((c
=shgetc(f
))));
505 if (c
=='+' || c
=='-') {
510 for (i
=0; i
<8 && (c
|32)=="infinity"[i
]; i
++)
511 if (i
<7) c
= shgetc(f
);
512 if (i
==3 || i
==8 || (i
>3 && pok
)) {
515 if (pok
) for (; i
>3; i
--) shunget(f
);
517 return sign
* INFINITY
;
519 if (!i
) for (i
=0; i
<3 && (c
|32)=="nan"[i
]; i
++)
520 if (i
<2) c
= shgetc(f
);
522 if (shgetc(f
) != '(') {
528 if (c
-'0'<10U || c
-'A'<26U || c
-'a'<26U || c
=='_')
530 if (c
==')') return NAN
;
537 while (i
--) shunget(f
);
553 return hexfloat(f
, bits
, emin
, sign
, pok
);
558 return decfloat(f
, c
, bits
, emin
, sign
, pok
);