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