|
54 | 54 | #define SIGNBIT 0x80000000L
|
55 | 55 | #define HIDDEN (1L << 23L)
|
56 | 56 | #define SIGN(fp) ((fp) & SIGNBIT)
|
| 57 | +#define EXPMASK 0xFFL |
57 | 58 | #define EXP(fp) (((fp) >> 23L) & 0xFF)
|
58 | 59 | #define MANT(fp) (((fp) & 0x7FFFFFL) | HIDDEN)
|
59 | 60 | #define PACK(s,e,m) ((s) | ((e) << 23L) | (m))
|
@@ -262,6 +263,9 @@ __extendsfdf2 (float a1)
|
262 | 263 | mant &= ~HIDDEN;
|
263 | 264 | }
|
264 | 265 | exp = exp - EXCESS + EXCESSD;
|
| 266 | + /* Handle inf and NaN */ |
| 267 | + if (exp == EXPMASK - EXCESS + EXCESSD) |
| 268 | + exp = EXPDMASK; |
265 | 269 | dl.l.upper |= exp << 20;
|
266 | 270 | dl.l.upper |= mant >> 3;
|
267 | 271 | dl.l.lower = mant << 29;
|
@@ -295,40 +299,52 @@ __truncdfsf2 (double a1)
|
295 | 299 | /* shift double mantissa 6 bits so we can round */
|
296 | 300 | sticky |= mant & ((1 << 6) - 1);
|
297 | 301 | mant >>= 6;
|
298 |
| - |
299 |
| - /* Check for underflow and denormals. */ |
300 |
| - if (exp <= 0) |
| 302 | + if (exp == EXPDMASK - EXCESSD + EXCESS) |
| 303 | + { |
| 304 | + exp = EXPMASK; |
| 305 | + mant = mant >> 1 | (mant & 1) | !!sticky; |
| 306 | + } |
| 307 | + else |
301 | 308 | {
|
302 |
| - if (exp < -24) |
| 309 | + /* Check for underflow and denormals. */ |
| 310 | + if (exp <= 0) |
303 | 311 | {
|
304 |
| - sticky |= mant; |
305 |
| - mant = 0; |
| 312 | + if (exp < -24) |
| 313 | + { |
| 314 | + sticky |= mant; |
| 315 | + mant = 0; |
| 316 | + } |
| 317 | + else |
| 318 | + { |
| 319 | + sticky |= mant & ((1 << (1 - exp)) - 1); |
| 320 | + mant >>= 1 - exp; |
| 321 | + } |
| 322 | + exp = 0; |
306 | 323 | }
|
307 |
| - else |
| 324 | + |
| 325 | + /* now round */ |
| 326 | + shift = 1; |
| 327 | + if ((mant & 1) && (sticky || (mant & 2))) |
308 | 328 | {
|
309 |
| - sticky |= mant & ((1 << (1 - exp)) - 1); |
310 |
| - mant >>= 1 - exp; |
311 |
| - } |
312 |
| - exp = 0; |
313 |
| - } |
314 |
| - |
315 |
| - /* now round */ |
316 |
| - shift = 1; |
317 |
| - if ((mant & 1) && (sticky || (mant & 2))) |
318 |
| - { |
319 |
| - int rounding = exp ? 2 : 1; |
| 329 | + int rounding = exp ? 2 : 1; |
320 | 330 |
|
321 |
| - mant += 1; |
| 331 | + mant += 1; |
322 | 332 |
|
323 |
| - /* did the round overflow? */ |
324 |
| - if (mant >= (HIDDEN << rounding)) |
| 333 | + /* did the round overflow? */ |
| 334 | + if (mant >= (HIDDEN << rounding)) |
| 335 | + { |
| 336 | + exp++; |
| 337 | + shift = rounding; |
| 338 | + } |
| 339 | + } |
| 340 | + /* shift down */ |
| 341 | + mant >>= shift; |
| 342 | + if (exp >= EXPMASK) |
325 | 343 | {
|
326 |
| - exp++; |
327 |
| - shift = rounding; |
| 344 | + exp = EXPMASK; |
| 345 | + mant = 0; |
328 | 346 | }
|
329 | 347 | }
|
330 |
| - /* shift down */ |
331 |
| - mant >>= shift; |
332 | 348 |
|
333 | 349 | mant &= ~HIDDEN;
|
334 | 350 |
|
@@ -432,6 +448,24 @@ __extenddfxf2 (double d)
|
432 | 448 | }
|
433 | 449 |
|
434 | 450 | exp = EXPD (dl) - EXCESSD + EXCESSX;
|
| 451 | + dl.l.upper &= MANTDMASK; |
| 452 | + |
| 453 | + /* Recover from a denorm. */ |
| 454 | + if (exp == -EXCESSD + EXCESSX) |
| 455 | + { |
| 456 | + exp++; |
| 457 | + while ((dl.l.upper & HIDDEND) == 0) |
| 458 | + { |
| 459 | + exp--; |
| 460 | + dl.l.upper = (dl.l.upper << 1) | (dl.l.lower >> 31); |
| 461 | + dl.l.lower = dl.l.lower << 1; |
| 462 | + } |
| 463 | + } |
| 464 | + |
| 465 | + /* Handle inf and NaN */ |
| 466 | + else if (exp == EXPDMASK - EXCESSD + EXCESSX) |
| 467 | + exp = EXPXMASK; |
| 468 | + |
435 | 469 | ldl.l.upper |= exp << 16;
|
436 | 470 | ldl.l.middle = HIDDENX;
|
437 | 471 | /* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */
|
@@ -464,9 +498,38 @@ __truncxfdf2 (long double ld)
|
464 | 498 | }
|
465 | 499 |
|
466 | 500 | exp = EXPX (ldl) - EXCESSX + EXCESSD;
|
467 |
| - /* ??? quick and dirty: keep `exp' sane */ |
468 |
| - if (exp >= EXPDMASK) |
469 |
| - exp = EXPDMASK - 1; |
| 501 | + /* Check for underflow and denormals. */ |
| 502 | + if (exp <= 0) |
| 503 | + { |
| 504 | + if (exp < -53) |
| 505 | + { |
| 506 | + ldl.l.middle = 0; |
| 507 | + ldl.l.lower = 0; |
| 508 | + } |
| 509 | + else if (exp < -30) |
| 510 | + { |
| 511 | + ldl.l.lower = (ldl.l.middle & MANTXMASK) >> ((1 - exp) - 32); |
| 512 | + ldl.l.middle &= ~MANTXMASK; |
| 513 | + } |
| 514 | + else |
| 515 | + { |
| 516 | + ldl.l.lower >>= 1 - exp; |
| 517 | + ldl.l.lower |= (ldl.l.middle & MANTXMASK) << (32 - (1 - exp)); |
| 518 | + ldl.l.middle = (ldl.l.middle & ~MANTXMASK) | (ldl.l.middle & MANTXMASK >> (1 - exp)); |
| 519 | + } |
| 520 | + exp = 0; |
| 521 | + } |
| 522 | + else if (exp == EXPXMASK - EXCESSX + EXCESSD) |
| 523 | + { |
| 524 | + exp = EXPDMASK; |
| 525 | + ldl.l.middle |= ldl.l.lower; |
| 526 | + } |
| 527 | + else if (exp >= EXPDMASK) |
| 528 | + { |
| 529 | + exp = EXPDMASK; |
| 530 | + ldl.l.middle = 0; |
| 531 | + ldl.l.lower = 0; |
| 532 | + } |
470 | 533 | dl.l.upper |= exp << (32 - (EXPDBITS + 1));
|
471 | 534 | /* +1-1: add one for sign bit, but take one off for explicit-integer-bit */
|
472 | 535 | dl.l.upper |= (ldl.l.middle & MANTXMASK) >> (EXPDBITS + 1 - 1);
|
@@ -511,10 +574,40 @@ __floatunsixf (unsigned long l)
|
511 | 574 |
|
512 | 575 | /* convert a long double to an int */
|
513 | 576 | long
|
514 |
| -__fixxfsi (long double ld) |
| 577 | +__fixxfsi (long double a) |
515 | 578 | {
|
516 |
| - long foo = __fixdfsi ((double) ld); |
517 |
| - return foo; |
| 579 | + union long_double_long ldl; |
| 580 | + long exp; |
| 581 | + long l; |
| 582 | + |
| 583 | + ldl.ld = a; |
| 584 | + |
| 585 | + exp = EXPX(ldl); |
| 586 | + if (exp == 0 && ldl.l.middle == 0 && ldl.l.lower == 0) |
| 587 | + return 0; |
| 588 | + |
| 589 | + exp = exp - EXCESSX - 64; |
| 590 | + |
| 591 | + if (exp > 0) |
| 592 | + { |
| 593 | + /* Return largest integer. */ |
| 594 | + return SIGNX (ldl) ? 0x80000000L : 0x7fffffffL; |
| 595 | + } |
| 596 | + |
| 597 | + if (exp <= -64) |
| 598 | + return 0; |
| 599 | + |
| 600 | + if (exp <= -32) |
| 601 | + { |
| 602 | + ldl.l.lower = ldl.l.middle >> (-exp - 32); |
| 603 | + } |
| 604 | + else if (exp < 0) |
| 605 | + { |
| 606 | + ldl.l.lower = ldl.l.lower >> -exp; |
| 607 | + ldl.l.lower |= ldl.l.middle << (32 + exp); |
| 608 | + } |
| 609 | + |
| 610 | + return SIGNX(ldl) ? -ldl.l.lower : ldl.l.lower; |
518 | 611 | }
|
519 | 612 |
|
520 | 613 | /* The remaining provide crude math support by working in double precision. */
|
|
0 commit comments