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