int_fast32_t f32_to_i32( float32_t a, uint_fast8_t roundingMode, bool exact ) { union ui32_f32 uA; uint_fast32_t uiA; bool sign; int_fast16_t exp; uint_fast32_t sig; uint_fast64_t sig64; int_fast16_t shiftCount; uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); sig = fracF32UI( uiA ); if ( (exp == 0xFF) && sig ) sign = 0; if ( exp ) sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<32; shiftCount = 0xAF - exp; if ( 0 < shiftCount ) { sig64 = softfloat_shiftRightJam64( sig64, shiftCount ); } return softfloat_roundPackToI32( sign, sig64, roundingMode, exact ); }
uint_fast32_t f128_to_ui32( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftCount; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); sig64 |= (sig0 != 0); shiftCount = 0x4028 - exp; if ( 0 < shiftCount ) { sig64 = softfloat_shiftRightJam64( sig64, shiftCount ); } return softfloat_roundPackToUI32( sign, sig64, roundingMode, exact ); }
float64_t softfloat_roundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig ) { uint_fast8_t roundingMode; bool roundNearEven; uint_fast16_t roundIncrement, roundBits; bool isTiny; uint_fast64_t uiZ; union ui64_f64 uZ; roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x200; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0x3FF : 0; } roundBits = sig & 0x3FF; if ( 0x7FD <= (uint16_t) exp ) { if ( exp < 0 ) { isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < -1) || (sig + roundIncrement < UINT64_C( 0x8000000000000000 )); sig = softfloat_shiftRightJam64( sig, -exp ); exp = 0; roundBits = sig & 0x3FF; if ( isTiny && roundBits ) { softfloat_raiseFlags( softfloat_flag_underflow ); } } else if ( (0x7FD < exp) || (UINT64_C( 0x8000000000000000 ) <= sig + roundIncrement) ) { softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); uiZ = packToF64UI( sign, 0x7FF, 0 ) - ! roundIncrement; goto uiZ; } } if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact; sig = (sig + roundIncrement)>>10; sig &= ~(uint_fast64_t) (! (roundBits ^ 0x200) & roundNearEven); uiZ = packToF64UI( sign, sig ? exp : 0, sig ); uiZ: uZ.ui = uiZ; return uZ.f; }
uint_fast32_t f128_to_ui32( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64; int_fast32_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) if ( (exp == 0x7FFF) && sig64 ) { #if (ui32_fromNaN == ui32_fromPosOverflow) sign = 0; #elif (ui32_fromNaN == ui32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return ui32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); shiftDist = 0x4023 - exp; if ( 0 < shiftDist ) { sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); } return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); }
uint_fast32_t f64_to_ui32( float64_t a, uint_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftCount = 0x42C - exp; if ( 0 < shiftCount ) sig = softfloat_shiftRightJam64( sig, shiftCount ); return softfloat_roundPackToUI32( sign, sig, roundingMode, exact ); }
uint_fast32_t extF80_to_ui32( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64; bool sign; int_fast32_t exp; uint_fast64_t sig; int_fast32_t shiftCount; uA.f = a; uiA64 = uA.s.signExp; sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; shiftCount = 0x4037 - exp; if ( shiftCount <= 0 ) shiftCount = 1; sig = softfloat_shiftRightJam64( sig, shiftCount ); return softfloat_roundPackToUI32( sign, sig, roundingMode, exact ); }
uint_fast32_t f128M_to_ui32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) { const uint32_t *aWPtr; uint32_t uiA96; bool sign; int32_t exp; uint64_t sig64; int32_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ aWPtr = (const uint32_t *) aPtr; uiA96 = aWPtr[indexWordHi( 4 )]; sign = signF128UI96( uiA96 ); exp = expF128UI96( uiA96 ); sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) if ( (exp == 0x7FFF) && sig64 ) { #if (ui32_fromNaN == ui32_fromPosOverflow) sign = 0; #elif (ui32_fromNaN == ui32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return ui32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); shiftDist = 0x4028 - exp; if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); return softfloat_roundPackToUI32( sign, sig64, roundingMode, exact ); }
uint_fast32_t extF80_to_ui32( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64; bool sign; int_fast32_t exp; uint_fast64_t sig; int_fast32_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.s.signExp; sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) if ( (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { #if (ui32_fromNaN == ui32_fromPosOverflow) sign = 0; #elif (ui32_fromNaN == ui32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return ui32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x4032 - exp; if ( shiftDist <= 0 ) shiftDist = 1; sig = softfloat_shiftRightJam64( sig, shiftDist ); return softfloat_roundPackToUI32( sign, sig, roundingMode, exact ); }
int_fast32_t f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) if ( (exp == 0x7FF) && sig ) { #if (i32_fromNaN == i32_fromPosOverflow) sign = 0; #elif (i32_fromNaN == i32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return i32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftDist = 0x42C - exp; if ( 0 < shiftDist ) sig = softfloat_shiftRightJam64( sig, shiftDist ); return softfloat_roundPackToI32( sign, sig, roundingMode, exact ); }
uint_fast32_t f128M_to_ui32( const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) { const uint32_t *aWPtr; uint32_t uiA96; int32_t exp; uint64_t sig64; int32_t shiftCount; aWPtr = (const uint32_t *) aPtr; uiA96 = aWPtr[indexWordHi( 4 )]; exp = expF128UI96( uiA96 ); sig64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )]; if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); if ( aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )] ) sig64 |= 1; shiftCount = 0x4028 - exp; if ( 0 < shiftCount ) { sig64 = softfloat_shiftRightJam64( sig64, shiftCount ); } return softfloat_roundPackToUI32( signF128UI96( uiA96 ), sig64, roundingMode, exact ); }
float32_t softfloat_mulAddF32( uint_fast32_t uiA, uint_fast32_t uiB, uint_fast32_t uiC, uint_fast8_t op ) { bool signA; int_fast16_t expA; uint_fast32_t sigA; bool signB; int_fast16_t expB; uint_fast32_t sigB; bool signC; int_fast16_t expC; uint_fast32_t sigC; bool signProd; uint_fast32_t magBits, uiZ; struct exp16_sig32 normExpSig; int_fast16_t expProd; uint_fast64_t sigProd; bool signZ; int_fast16_t expZ; uint_fast32_t sigZ; int_fast16_t expDiff; uint_fast64_t sig64Z, sig64C; int_fast8_t shiftCount; union ui32_f32 uZ; signA = signF32UI( uiA ); expA = expF32UI( uiA ); sigA = fracF32UI( uiA ); signB = signF32UI( uiB ); expB = expF32UI( uiB ); sigB = fracF32UI( uiB ); signC = signF32UI( uiC ) ^ (op == softfloat_mulAdd_subC); expC = expF32UI( uiC ); sigC = fracF32UI( uiC ); signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd); if ( expA == 0xFF ) { if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN_ABC; magBits = expB | sigB; goto infProdArg; } if ( expB == 0xFF ) { if ( sigB ) goto propagateNaN_ABC; magBits = expA | sigA; goto infProdArg; } if ( expC == 0xFF ) { if ( sigC ) { uiZ = 0; goto propagateNaN_ZC; } uiZ = uiC; goto uiZ; } if ( ! expA ) { if ( ! sigA ) goto zeroProd; normExpSig = softfloat_normSubnormalF32Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zeroProd; normExpSig = softfloat_normSubnormalF32Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } expProd = expA + expB - 0x7E; sigA = (sigA | 0x00800000)<<7; sigB = (sigB | 0x00800000)<<7; sigProd = (uint_fast64_t) sigA * sigB; if ( sigProd < UINT64_C( 0x2000000000000000 ) ) { --expProd; sigProd <<= 1; } signZ = signProd; if ( ! expC ) { if ( ! sigC ) { expZ = expProd - 1; sigZ = softfloat_shortShiftRightJam64( sigProd, 31 ); goto roundPack; } normExpSig = softfloat_normSubnormalF32Sig( sigC ); expC = normExpSig.exp; sigC = normExpSig.sig; } sigC = (sigC | 0x00800000)<<6; expDiff = expProd - expC; if ( signProd == signC ) { if ( expDiff <= 0 ) { expZ = expC; sigZ = sigC + softfloat_shiftRightJam64( sigProd, 32 - expDiff ); } else { expZ = expProd; sig64Z = sigProd + softfloat_shiftRightJam64( (uint_fast64_t) sigC<<32, expDiff ); sigZ = softfloat_shortShiftRightJam64( sig64Z, 32 ); } if ( sigZ < 0x40000000 ) { --expZ; sigZ <<= 1; } } else { sig64C = (uint_fast64_t) sigC<<32; if ( expDiff < 0 ) { signZ = signC; expZ = expC; sig64Z = sig64C - softfloat_shiftRightJam64( sigProd, -expDiff ); } else if ( ! expDiff ) { expZ = expProd; sig64Z = sigProd - sig64C; if ( ! sig64Z ) goto completeCancellation; if ( sig64Z & UINT64_C( 0x8000000000000000 ) ) { signZ ^= 1; sig64Z = -sig64Z; } } else { expZ = expProd; sig64Z = sigProd - softfloat_shiftRightJam64( sig64C, expDiff ); } shiftCount = softfloat_countLeadingZeros64( sig64Z ) - 1; expZ -= shiftCount; shiftCount -= 32; if ( shiftCount < 0 ) { sigZ = softfloat_shortShiftRightJam64( sig64Z, -shiftCount ); } else { sigZ = (uint_fast32_t) sig64Z<<shiftCount; } } roundPack: return softfloat_roundPackToF32( signZ, expZ, sigZ ); propagateNaN_ABC: uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); goto propagateNaN_ZC; infProdArg: if ( magBits ) { uiZ = packToF32UI( signProd, 0xFF, 0 ); if ( expC != 0xFF ) goto uiZ; if ( sigC ) goto propagateNaN_ZC; if ( signProd == signC ) goto uiZ; } invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; propagateNaN_ZC: uiZ = softfloat_propagateNaNF32UI( uiZ, uiC ); goto uiZ; zeroProd: uiZ = uiC; if ( ! (expC | sigC) && (signProd != signC) ) { completeCancellation: uiZ = packToF32UI( softfloat_roundingMode == softfloat_round_min, 0, 0 ); } uiZ: uZ.ui = uiZ; return uZ.f; }
float64_t softfloat_addMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ ) { int_fast16_t expA; uint_fast64_t sigA; int_fast16_t expB; uint_fast64_t sigB; int_fast16_t expDiff; uint_fast64_t uiZ; int_fast16_t expZ; uint_fast64_t sigZ; union ui64_f64 uZ; expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); expDiff = expA - expB; sigA <<= 9; sigB <<= 9; if ( ! expDiff ) { if ( expA == 0x7FF ) { if ( sigA | sigB ) goto propagateNaN; uiZ = uiA; goto uiZ; } if ( ! expA ) { uiZ = packToF64UI( signZ, 0, (uiA + uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ); goto uiZ; } expZ = expA; sigZ = UINT64_C( 0x4000000000000000 ) + sigA + sigB; } else { if ( expDiff < 0 ) { if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; uiZ = packToF64UI( signZ, 0x7FF, 0 ); goto uiZ; } expZ = expB; sigA += expA ? UINT64_C( 0x2000000000000000 ) : sigA; sigA = softfloat_shiftRightJam64( sigA, -expDiff ); } else { if ( expA == 0x7FF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } expZ = expA; sigB += expB ? UINT64_C( 0x2000000000000000 ) : sigB; sigB = softfloat_shiftRightJam64( sigB, expDiff ); } sigZ = UINT64_C( 0x2000000000000000 ) + sigA + sigB; if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { --expZ; sigZ <<= 1; } } return softfloat_roundPackToF64( signZ, expZ, sigZ ); propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); uiZ: uZ.ui = uiZ; return uZ.f; }
float64_t softfloat_subMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ ) { int_fast16_t expA; uint_fast64_t sigA; int_fast16_t expB; uint_fast64_t sigB; int_fast16_t expDiff; uint_fast64_t uiZ; int_fast16_t expZ; uint_fast64_t sigZ; union ui64_f64 uZ; expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); expDiff = expA - expB; sigA <<= 10; sigB <<= 10; if ( 0 < expDiff ) goto expABigger; if ( expDiff < 0 ) goto expBBigger; if ( expA == 0x7FF ) { if ( sigA | sigB ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; goto uiZ; } if ( ! expA ) { expA = 1; expB = 1; } if ( sigB < sigA ) goto aBigger; if ( sigA < sigB ) goto bBigger; uiZ = packToF64UI( softfloat_roundingMode == softfloat_round_min, 0, 0 ); goto uiZ; expBBigger: if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; uiZ = packToF64UI( signZ ^ 1, 0x7FF, 0 ); goto uiZ; } sigA += expA ? UINT64_C( 0x4000000000000000 ) : sigA; sigA = softfloat_shiftRightJam64( sigA, -expDiff ); sigB |= UINT64_C( 0x4000000000000000 ); bBigger: signZ ^= 1; expZ = expB; sigZ = sigB - sigA; goto normRoundPack; expABigger: if ( expA == 0x7FF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } sigB += expB ? UINT64_C( 0x4000000000000000 ) : sigB; sigB = softfloat_shiftRightJam64( sigB, expDiff ); sigA |= UINT64_C( 0x4000000000000000 ); aBigger: expZ = expA; sigZ = sigA - sigB; normRoundPack: return softfloat_normRoundPackToF64( signZ, expZ - 1, sigZ ); propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); uiZ: uZ.ui = uiZ; return uZ.f; }
void softfloat_roundPackMToExtF80M( bool sign, int32_t exp, uint32_t *extSigPtr, uint_fast8_t roundingPrecision, struct extFloat80M *zSPtr ) { uint_fast8_t roundingMode; bool roundNearEven; uint64_t sig, roundIncrement, roundMask, roundBits; bool isTiny; uint32_t sigExtra; bool doIncrement; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; if ( roundingPrecision == 80 ) goto precision80; if ( roundingPrecision == 64 ) { roundIncrement = UINT64_C( 0x0000000000000400 ); roundMask = UINT64_C( 0x00000000000007FF ); } else if ( roundingPrecision == 32 ) { roundIncrement = UINT64_C( 0x0000008000000000 ); roundMask = UINT64_C( 0x000000FFFFFFFFFF ); } else { goto precision80; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( extSigPtr[indexWordLo( 3 )] ) sig |= 1; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? roundMask : 0; } roundBits = sig & roundMask; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x7FFD <= (uint32_t) (exp - 1) ) { if ( exp <= 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < 0) || (sig <= (uint64_t) (sig + roundIncrement)); sig = softfloat_shiftRightJam64( sig, 1 - exp ); roundBits = sig & roundMask; if ( roundBits ) { if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= roundMask + 1; } #endif } sig += roundIncrement; exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) ) { goto overflow; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig = (sig & ~roundMask) | (roundMask + 1); goto packReturn; } #endif } sig += roundIncrement; if ( sig < roundIncrement ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; goto packReturn; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ precision80: sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x7FFD <= (uint32_t) (exp - 1) ) { if ( exp <= 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < 0) || ! doIncrement || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr ); exp = 0; sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; sigExtra = extSigPtr[indexWordLo( 3 )]; if ( sigExtra ) { if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= 1; goto packReturn; } #endif } doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( doIncrement ) { ++sig; sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); } goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) && doIncrement) ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ roundMask = 0; overflow: softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) || (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ) { exp = 0x7FFF; sig = UINT64_C( 0x8000000000000000 ); } else { exp = 0x7FFE; sig = ~roundMask; } goto packReturn; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= 1; goto packReturn; } #endif } if ( doIncrement ) { ++sig; if ( ! sig ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } else { sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ packReturn: zSPtr->signExp = packToExtF80UI64( sign, exp ); zSPtr->signif = sig; }
float64_t softfloat_addMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ ) { int_fast16_t expA; uint_fast64_t sigA; int_fast16_t expB; uint_fast64_t sigB; int_fast16_t expDiff; uint_fast64_t uiZ; int_fast16_t expZ; uint_fast64_t sigZ; union ui64_f64 uZ; expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); expDiff = expA - expB; sigA <<= 9; sigB <<= 9; if ( ! expDiff ) { if ( expA == 0x7FF ) { if ( sigA | sigB ) goto propagateNaN; uiZ = uiA; goto uiZ; } #ifdef IBM_IEEE if ( ! expA ) { sigZ = (uiA + uiB) & UINT64_C(0x7FFFFFFFFFFFFFFF); /* Sum the significands and exclude sign bits */ if (!(sigZ & 0XFFF0000000000000) && sigZ) { /* if exp zero and sig non-zero, then subnormal */ softfloat_raw.Incre = false; /* Result was not incremented */ softfloat_raw.Inexact = false; /* Result is not inexact */ softfloat_raw.Sig64 = sigZ << 10; /* 32 + 7; save rounded significand for scaling */ softfloat_raw.Sig0 = 0; /* Zero bits 64-128 of rounded result */ softfloat_raw.Exp = -1022; /* Save semi-unbiased exponent */ softfloat_raw.Sign = signZ; /* Save result sign */ softfloat_raw.Tiny = true; /* Indicate a subnormal result */ softfloat_exceptionFlags |= softfloat_flag_tiny; /* nonzero result is tiny */ } uiZ = packToF64UI(signZ, 0, sigZ); /* Pack up a zero or a subnormal */ goto uiZ; } #else if ( ! expA ) { uiZ = packToF64UI( signZ, 0, (uiA + uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ); goto uiZ; } #endif /* IBM_IEEE */ expZ = expA; sigZ = UINT64_C( 0x4000000000000000 ) + sigA + sigB; } else { if ( expDiff < 0 ) { if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; uiZ = packToF64UI( signZ, 0x7FF, 0 ); goto uiZ; } expZ = expB; sigA += expA ? UINT64_C( 0x2000000000000000 ) : sigA; sigA = softfloat_shiftRightJam64( sigA, -expDiff ); } else { if ( expA == 0x7FF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } expZ = expA; sigB += expB ? UINT64_C( 0x2000000000000000 ) : sigB; sigB = softfloat_shiftRightJam64( sigB, expDiff ); } sigZ = UINT64_C( 0x2000000000000000 ) + sigA + sigB; if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { --expZ; sigZ <<= 1; } } return softfloat_roundPackToF64( signZ, expZ, sigZ ); propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); uiZ: uZ.ui = uiZ; return uZ.f; }
float64_t softfloat_mulAddF64( uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) { bool signA; int_fast16_t expA; uint64_t sigA; bool signB; int_fast16_t expB; uint64_t sigB; bool signC; int_fast16_t expC; uint64_t sigC; bool signZ; uint64_t magBits, uiZ; struct exp16_sig64 normExpSig; int_fast16_t expZ; uint32_t sig128Z[4]; uint64_t sigZ; int_fast16_t shiftCount, expDiff; uint32_t sig128C[4]; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ signA = signF64UI( uiA ); expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); signB = signF64UI( uiB ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); signC = signF64UI( uiC ) ^ (op == softfloat_mulAdd_subC); expC = expF64UI( uiC ); sigC = fracF64UI( uiC ); signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FF ) { if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN_ABC; magBits = expB | sigB; goto infProdArg; } if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN_ABC; magBits = expA | sigA; goto infProdArg; } if ( expC == 0x7FF ) { if ( sigC ) { uiZ = 0; goto propagateNaN_ZC; } uiZ = uiC; goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! sigA ) goto zeroProd; normExpSig = softfloat_normSubnormalF64Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zeroProd; normExpSig = softfloat_normSubnormalF64Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FE; sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<11; softfloat_mul64To128M( sigA, sigB, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; shiftCount = 0; if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { --expZ; shiftCount = -1; } if ( ! expC ) { if ( ! sigC ) { if ( shiftCount ) sigZ <<= 1; goto sigZ; } normExpSig = softfloat_normSubnormalF64Sig( sigC ); expC = normExpSig.exp; sigC = normExpSig.sig; } sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<10; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expZ - expC; if ( expDiff < 0 ) { expZ = expC; if ( (signZ == signC) || (expDiff < -1) ) { shiftCount -= expDiff; if ( shiftCount) { sigZ = softfloat_shiftRightJam64( sigZ, shiftCount ); } } else { if ( ! shiftCount ) { softfloat_shortShiftRight128M( sig128Z, 1, sig128Z ); } } } else { if ( shiftCount ) softfloat_add128M( sig128Z, sig128Z, sig128Z ); if ( ! expDiff ) { sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; } else { sig128C[indexWord( 4, 3 )] = sigC>>32; sig128C[indexWord( 4, 2 )] = sigC; sig128C[indexWord( 4, 1 )] = 0; sig128C[indexWord( 4, 0 )] = 0; softfloat_shiftRightJam128M( sig128C, expDiff, sig128C ); } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( signZ == signC ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff <= 0 ) { sigZ += sigC; } else { softfloat_add128M( sig128Z, sig128C, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; } if ( sigZ & UINT64_C( 0x8000000000000000 ) ) { ++expZ; sigZ = softfloat_shortShiftRightJam64( sigZ, 1 ); } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff < 0 ) { signZ = signC; if ( expDiff < -1 ) { sigZ = sigC - sigZ; if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) { sigZ = (sigZ - 1) | 1; } if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { --expZ; sigZ <<= 1; } goto roundPack; } else { sig128C[indexWord( 4, 3 )] = sigC>>32; sig128C[indexWord( 4, 2 )] = sigC; sig128C[indexWord( 4, 1 )] = 0; sig128C[indexWord( 4, 0 )] = 0; softfloat_sub128M( sig128C, sig128Z, sig128Z ); } } else if ( ! expDiff ) {
extFloat80_t softfloat_roundPackToExtF80( bool sign, int_fast32_t exp, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingPrecision ) { uint_fast8_t roundingMode; bool roundNearEven; uint_fast64_t roundIncrement, roundMask, roundBits; bool isTiny, doIncrement; struct uint64_extra sig64Extra; union { struct extFloat80M s; extFloat80_t f; } uZ; roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); if ( roundingPrecision == 80 ) goto precision80; if ( roundingPrecision == 64 ) { roundIncrement = UINT64_C( 0x0000000000000400 ); roundMask = UINT64_C( 0x00000000000007FF ); } else if ( roundingPrecision == 32 ) { roundIncrement = UINT64_C( 0x0000008000000000 ); roundMask = UINT64_C( 0x000000FFFFFFFFFF ); } else { goto precision80; } sig |= (sigExtra != 0); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? roundMask : 0; } roundBits = sig & roundMask; if ( 0x7FFD <= (uint32_t) (exp - 1) ) { if ( exp <= 0 ) { isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < 0) || (sig <= (uint64_t) (sig + roundIncrement)); sig = softfloat_shiftRightJam64( sig, 1 - exp ); roundBits = sig & roundMask; if ( isTiny && roundBits ) { softfloat_raiseFlags( softfloat_flag_underflow ); } if ( roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } sig += roundIncrement; exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) ) { goto overflow; } } if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact; sig = (uint64_t) (sig + roundIncrement); if ( sig < roundIncrement ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; if ( ! sig ) exp = 0; goto packReturn; precision80: doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( 0x7FFD <= (uint32_t) (exp - 1) ) { if ( exp <= 0 ) { isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < 0) || ! doIncrement || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); sig64Extra = softfloat_shiftRightJam64Extra( sig, sigExtra, 1 - exp ); sig = sig64Extra.v; sigExtra = sig64Extra.extra; if ( isTiny && sigExtra ) { softfloat_raiseFlags( softfloat_flag_underflow ); } if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } exp = 0; if ( doIncrement ) { ++sig; sig &= ~(uint_fast64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); } goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) && doIncrement) ) { roundMask = 0; overflow: softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) || (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ) { exp = 0x7FFF; sig = UINT64_C( 0x8000000000000000 ); } else { exp = 0x7FFE; sig = ~roundMask; } goto packReturn; } } if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; if ( doIncrement ) { ++sig; if ( ! sig ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } else { sig &= ~(uint_fast64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); } } else { if ( ! sig ) exp = 0; } packReturn: uZ.s.signExp = packToExtF80UI64( sign, exp ); uZ.s.signif = sig; return uZ.f; }
float64_t softfloat_mulAddF64( uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) { bool signA; int_fast16_t expA; uint_fast64_t sigA; bool signB; int_fast16_t expB; uint_fast64_t sigB; bool signC; int_fast16_t expC; uint_fast64_t sigC; bool signZ; uint_fast64_t magBits, uiZ; struct exp16_sig64 normExpSig; int_fast16_t expZ; struct uint128 sig128Z; uint_fast64_t sigZ; int_fast16_t expDiff; struct uint128 sig128C; int_fast8_t shiftCount; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ signA = signF64UI( uiA ); expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); signB = signF64UI( uiB ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); signC = signF64UI( uiC ) ^ (op == softfloat_mulAdd_subC); expC = expF64UI( uiC ); sigC = fracF64UI( uiC ); signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FF ) { if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN_ABC; magBits = expB | sigB; goto infProdArg; } if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN_ABC; magBits = expA | sigA; goto infProdArg; } if ( expC == 0x7FF ) { if ( sigC ) { uiZ = 0; goto propagateNaN_ZC; } uiZ = uiC; goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! sigA ) goto zeroProd; normExpSig = softfloat_normSubnormalF64Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zeroProd; normExpSig = softfloat_normSubnormalF64Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FE; sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<10; sig128Z = softfloat_mul64To128( sigA, sigB ); if ( sig128Z.v64 < UINT64_C( 0x2000000000000000 ) ) { --expZ; sig128Z = softfloat_add128( sig128Z.v64, sig128Z.v0, sig128Z.v64, sig128Z.v0 ); } if ( ! expC ) { if ( ! sigC ) { --expZ; sigZ = sig128Z.v64<<1 | (sig128Z.v0 != 0); goto roundPack; } normExpSig = softfloat_normSubnormalF64Sig( sigC ); expC = normExpSig.exp; sigC = normExpSig.sig; } sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<9; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expZ - expC; if ( expDiff < 0 ) { expZ = expC; if ( (signZ == signC) || (expDiff < -1) ) { sig128Z.v64 = softfloat_shiftRightJam64( sig128Z.v64, -expDiff ); } else { sig128Z = softfloat_shortShiftRightJam128( sig128Z.v64, sig128Z.v0, 1 ); } } else if ( expDiff ) { sig128C = softfloat_shiftRightJam128( sigC, 0, expDiff ); } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( signZ == signC ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff <= 0 ) { sigZ = (sigC + sig128Z.v64) | (sig128Z.v0 != 0); } else { sig128Z = softfloat_add128( sig128Z.v64, sig128Z.v0, sig128C.v64, sig128C.v0 ); sigZ = sig128Z.v64 | (sig128Z.v0 != 0); } if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { --expZ; sigZ <<= 1; } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff < 0 ) { signZ = signC; sig128Z = softfloat_sub128( sigC, 0, sig128Z.v64, sig128Z.v0 ); } else if ( ! expDiff ) { sig128Z.v64 = sig128Z.v64 - sigC; if ( ! (sig128Z.v64 | sig128Z.v0) ) goto completeCancellation; if ( sig128Z.v64 & UINT64_C( 0x8000000000000000 ) ) { signZ ^= 1; sig128Z = softfloat_sub128( 0, 0, sig128Z.v64, sig128Z.v0 ); } } else { sig128Z = softfloat_sub128( sig128Z.v64, sig128Z.v0, sig128C.v64, sig128C.v0 ); } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( ! sig128Z.v64 ) { expZ -= 64; sig128Z.v64 = sig128Z.v0; sig128Z.v0 = 0; } shiftCount = softfloat_countLeadingZeros64( sig128Z.v64 ) - 1; expZ -= shiftCount; if ( shiftCount < 0 ) { sigZ = softfloat_shortShiftRightJam64( sig128Z.v64, -shiftCount ); } else { sig128Z = softfloat_shortShiftLeft128( sig128Z.v64, sig128Z.v0, shiftCount ); sigZ = sig128Z.v64; } sigZ |= (sig128Z.v0 != 0); } roundPack: return softfloat_roundPackToF64( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN_ABC: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); goto propagateNaN_ZC; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infProdArg: if ( magBits ) { uiZ = packToF64UI( signZ, 0x7FF, 0 ); if ( expC != 0x7FF ) goto uiZ; if ( sigC ) goto propagateNaN_ZC; if ( signZ == signC ) goto uiZ; } invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; propagateNaN_ZC: uiZ = softfloat_propagateNaNF64UI( uiZ, uiC ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zeroProd: uiZ = uiC; if ( ! (expC | sigC) && (signZ != signC) ) { completeCancellation: uiZ = packToF64UI( softfloat_roundingMode == softfloat_round_min, 0, 0 ); } uiZ: uZ.ui = uiZ; return uZ.f; }