------------------------------------------------------------------ */ decSetSubnormal -- process value whose exponent is <Emin */ / dn is the number (used as input as well as output; it may have */ an allowed subnormal value, which may need to be rounded) */ set is the context [used for the rounding mode] */ residue is any pending residue
| 7424 | /* necessary. Underflow is set if the result is Inexact. */ |
| 7425 | /* ------------------------------------------------------------------ */ |
| 7426 | static void decSetSubnormal(decNumber *dn, decContext *set, Int *residue, |
| 7427 | uInt *status) { |
| 7428 | decContext workset; // work |
| 7429 | Int etiny, adjust; // .. |
| 7430 | |
| 7431 | #if DECSUBSET |
| 7432 | // simple set to zero and 'hard underflow' for subset |
| 7433 | if (!set->extended) { |
| 7434 | decNumberZero(dn); |
| 7435 | // always full overflow |
| 7436 | *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded; |
| 7437 | return; |
| 7438 | } |
| 7439 | #endif |
| 7440 | |
| 7441 | // Full arithmetic -- allow subnormals, rounded to minimum exponent |
| 7442 | // (Etiny) if needed |
| 7443 | etiny=set->emin-(set->digits-1); // smallest allowed exponent |
| 7444 | |
| 7445 | if ISZERO(dn) { // value is zero |
| 7446 | // residue can never be non-zero here |
| 7447 | #if DECCHECK |
| 7448 | if (*residue!=0) { |
| 7449 | printf("++ Subnormal 0 residue %ld\n", (LI)*residue); |
| 7450 | *status|=DEC_Invalid_operation; |
| 7451 | } |
| 7452 | #endif |
| 7453 | if (dn->exponent<etiny) { // clamp required |
| 7454 | dn->exponent=etiny; |
| 7455 | *status|=DEC_Clamped; |
| 7456 | } |
| 7457 | return; |
| 7458 | } |
| 7459 | |
| 7460 | *status|=DEC_Subnormal; // have a non-zero subnormal |
| 7461 | adjust=etiny-dn->exponent; // calculate digits to remove |
| 7462 | if (adjust<=0) { // not out of range; unrounded |
| 7463 | // residue can never be non-zero here, except in the Nmin-residue |
| 7464 | // case (which is a subnormal result), so can take fast-path here |
| 7465 | // it may already be inexact (from setting the coefficient) |
| 7466 | if (*status&DEC_Inexact) *status|=DEC_Underflow; |
| 7467 | return; |
| 7468 | } |
| 7469 | |
| 7470 | // adjust>0, so need to rescale the result so exponent becomes Etiny |
| 7471 | // [this code is similar to that in rescale] |
| 7472 | workset=*set; // clone rounding, etc. |
| 7473 | workset.digits=dn->digits-adjust; // set requested length |
| 7474 | workset.emin-=adjust; // and adjust emin to match |
| 7475 | // [note that the latter can be <1, here, similar to Rescale case] |
| 7476 | decSetCoeff(dn, &workset, dn->lsu, dn->digits, residue, status); |
| 7477 | decApplyRound(dn, &workset, *residue, status); |
| 7478 | |
| 7479 | // Use 754 default rule: Underflow is set iff Inexact |
| 7480 | // [independent of whether trapped] |
| 7481 | if (*status&DEC_Inexact) *status|=DEC_Underflow; |
| 7482 | |
| 7483 | // if rounded up a 999s case, exponent will be off by one; adjust |
no test coverage detected