extFloat80_t extF80_roundToInt( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64, signUI64; int_fast32_t exp; uint_fast64_t sigA; uint_fast16_t uiZ64; uint_fast64_t sigZ; struct exp32_sig64 normExpSig; struct uint128 uiZ; uint_fast64_t lastBitMask, roundBitsMask; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.s.signExp; signUI64 = uiA64 & packToExtF80UI64( 1, 0 ); exp = expExtF80UI64( uiA64 ); sigA = uA.s.signif; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! (sigA & UINT64_C( 0x8000000000000000 )) && (exp != 0x7FFF) ) { if ( ! sigA ) { uiZ64 = signUI64; sigZ = 0; goto uiZ; } normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); exp += normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x403E <= exp ) { if ( exp == 0x7FFF ) { if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { uiZ = softfloat_propagateNaNExtF80UI( uiA64, sigA, 0, 0 ); uiZ64 = uiZ.v64; sigZ = uiZ.v0; goto uiZ; } sigZ = UINT64_C( 0x8000000000000000 ); } else { sigZ = sigA; } uiZ64 = signUI64 | exp; goto uiZ; } if ( exp <= 0x3FFE ) { if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; switch ( roundingMode ) { case softfloat_round_near_even: if ( ! (sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) break; case softfloat_round_near_maxMag: if ( exp == 0x3FFE ) goto mag1; break; case softfloat_round_min: if ( signUI64 ) goto mag1; break; case softfloat_round_max: if ( ! signUI64 ) goto mag1; break; } uiZ64 = signUI64; sigZ = 0; goto uiZ; mag1: uiZ64 = signUI64 | 0x3FFF; sigZ = UINT64_C( 0x8000000000000000 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ64 = signUI64 | exp; lastBitMask = (uint_fast64_t) 1<<(0x403E - exp); roundBitsMask = lastBitMask - 1; sigZ = sigA; if ( roundingMode == softfloat_round_near_maxMag ) { sigZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_near_even ) {
extFloat80_t extF80_mul( extFloat80_t a, extFloat80_t b ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64; uint_fast64_t uiA0; bool signA; int_fast32_t expA; uint_fast64_t sigA; union { struct extFloat80M s; extFloat80_t f; } uB; uint_fast16_t uiB64; uint_fast64_t uiB0; bool signB; int_fast32_t expB; uint_fast64_t sigB; bool signZ; uint_fast64_t magBits; struct exp32_sig64 normExpSig; int_fast32_t expZ; struct uint128 sig128Z, uiZ; uint_fast16_t uiZ64; uint_fast64_t uiZ0; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.s.signExp; uiA0 = uA.s.signif; signA = signExtF80UI64( uiA64 ); expA = expExtF80UI64( uiA64 ); sigA = uiA0; uB.f = b; uiB64 = uB.s.signExp; uiB0 = uB.s.signif; signB = signExtF80UI64( uiB64 ); expB = expExtF80UI64( uiB64 ); sigB = uiB0; signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FFF ) { if ( (sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) || ((expB == 0x7FFF) && (sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) ) { goto propagateNaN; } magBits = expB | sigB; goto infArg; } if ( expB == 0x7FFF ) { if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; magBits = expA | sigA; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) expA = 1; if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); expA += normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) expB = 1; if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalExtF80Sig( sigB ); expB += normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FFE; sig128Z = softfloat_mul64To128( sigA, sigB ); if ( sig128Z.v64 < UINT64_C( 0x8000000000000000 ) ) { --expZ; sig128Z = softfloat_add128( sig128Z.v64, sig128Z.v0, sig128Z.v64, sig128Z.v0 ); } return softfloat_roundPackToExtF80( signZ, expZ, sig128Z.v64, sig128Z.v0, extF80_roundingPrecision ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); uiZ64 = uiZ.v64; uiZ0 = uiZ.v0; goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ64 = defaultNaNExtF80UI64; uiZ0 = defaultNaNExtF80UI0; } else { uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); uiZ0 = UINT64_C( 0x8000000000000000 ); } goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ64 = packToExtF80UI64( signZ, 0 ); uiZ0 = 0; uiZ: uZ.s.signExp = uiZ64; uZ.s.signif = uiZ0; return uZ.f; }
extFloat80_t softfloat_addMagsExtF80( uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0, bool signZ ) { int_fast32_t expA; uint_fast64_t sigA; int_fast32_t expB; uint_fast64_t sigB; int_fast32_t expDiff; uint_fast16_t uiZ64; uint_fast64_t uiZ0, sigZ, sigZExtra; struct exp32_sig64 normExpSig; int_fast32_t expZ; struct uint64_extra sig64Extra; struct uint128 uiZ; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expA = expExtF80UI64( uiA64 ); sigA = uiA0; expB = expExtF80UI64( uiB64 ); sigB = uiB0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; if ( ! expDiff ) { if ( expA == 0x7FFF ) { if ( (sigA | sigB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { goto propagateNaN; } uiZ64 = uiA64; uiZ0 = uiA0; goto uiZ; } sigZ = sigA + sigB; sigZExtra = 0; if ( ! expA ) { normExpSig = softfloat_normSubnormalExtF80Sig( sigZ ); expZ = normExpSig.exp + 1; sigZ = normExpSig.sig; goto roundAndPack; } expZ = expA; goto shiftRight1; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expDiff < 0 ) { if ( expB == 0x7FFF ) { if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); uiZ0 = uiB0; goto uiZ; } expZ = expB; if ( ! expA ) { ++expDiff; sigZExtra = 0; if ( ! expDiff ) goto newlyAligned; } sig64Extra = softfloat_shiftRightJam64Extra( sigA, 0, -expDiff ); sigA = sig64Extra.v; sigZExtra = sig64Extra.extra; } else { if ( expA == 0x7FFF ) { if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = uiA64; uiZ0 = uiA0; goto uiZ; } expZ = expA; if ( ! expB ) { --expDiff; sigZExtra = 0; if ( ! expDiff ) goto newlyAligned; } sig64Extra = softfloat_shiftRightJam64Extra( sigB, 0, expDiff ); sigB = sig64Extra.v; sigZExtra = sig64Extra.extra; } newlyAligned: sigZ = sigA + sigB; if ( sigZ & UINT64_C( 0x8000000000000000 ) ) goto roundAndPack; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftRight1: sig64Extra = softfloat_shortShiftRightJam64Extra( sigZ, sigZExtra, 1 ); sigZ = sig64Extra.v | UINT64_C( 0x8000000000000000 ); sigZExtra = sig64Extra.extra; ++expZ; roundAndPack: return softfloat_roundPackToExtF80( signZ, expZ, sigZ, sigZExtra, extF80_roundingPrecision ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); uiZ64 = uiZ.v64; uiZ0 = uiZ.v0; uiZ: uZ.s.signExp = uiZ64; uZ.s.signif = uiZ0; return uZ.f; }