float32_t f64_to_f32( float64_t a ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; uint_fast32_t uiZ, sig32; union ui32_f32 uZ; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp == 0x7FF ) { uiZ = sig ? softfloat_commonNaNToF32UI( softfloat_f64UIToCommonNaN( uiA ) ) : packToF32UI( sign, 0xFF, 0 ); goto uiZ; } sig32 = softfloat_shortShift64RightJam( sig, 22 ); if ( ! ( exp | sig32 ) ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } return softfloat_roundPackToF32( sign, exp - 0x381, sig32 | 0x40000000 ); uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t i64_to_f32( int_fast64_t a ) { bool sign; uint_fast64_t absA; int shiftCount; union ui32_f32 u; uint_fast32_t sig; sign = ( a < 0 ); absA = sign ? - (uint_fast64_t) a : a; shiftCount = softfloat_countLeadingZeros64( absA ) - 40; if ( 0 <= shiftCount ) { u.ui = a ? packToF32UI( sign, 0x95 - shiftCount, (uint_fast32_t) absA<<shiftCount ) : 0; return u.f; } else { shiftCount += 7; sig = ( shiftCount < 0 ) ? softfloat_shortShift64RightJam( absA, - shiftCount ) : (uint_fast32_t) absA<<shiftCount; return softfloat_roundPackToF32( sign, 0x9C - shiftCount, sig ); } }
float32_t extF80M_to_f32( const extFloat80_t *aPtr ) { const struct extFloat80M *aSPtr; uint_fast16_t uiA64; bool sign; int32_t exp; uint64_t sig; struct commonNaN commonNaN; uint32_t uiZ, sig32; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ aSPtr = (const struct extFloat80M *) aPtr; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiA64 = aSPtr->signExp; sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = aSPtr->signif; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { softfloat_extF80MToCommonNaN( aSPtr, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { if ( ! sig ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } exp += softfloat_normExtF80SigM( &sig ); } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig32 = softfloat_shortShiftRightJam64( sig, 33 ); exp -= 0x3F81; if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF32( sign, exp, sig32 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t f128M_to_f32( const float128_t *aPtr ) { const uint32_t *aWPtr; uint32_t uiA96; bool sign; int32_t exp; uint64_t frac64; struct commonNaN commonNaN; uint32_t uiZ, frac32; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ aWPtr = (const uint32_t *) aPtr; uiA96 = aWPtr[indexWordHi( 4 )]; sign = signF128UI96( uiA96 ); exp = expF128UI96( uiA96 ); frac64 = (uint64_t) fracF128UI96( uiA96 )<<32 | aWPtr[indexWord( 4, 2 )] | ((aWPtr[indexWord( 4, 1 )] | aWPtr[indexWord( 4, 0 )]) != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( frac64 ) { softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac32 = softfloat_shortShiftRightJam64( frac64, 18 ); if ( ! (exp | frac32) ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ exp -= 0x3F81; if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF32( sign, exp, frac32 | 0x40000000 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t f128_to_f32( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t frac64; struct commonNaN commonNaN; uint_fast32_t uiZ, frac32; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); frac64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( frac64 ) { softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac32 = softfloat_shortShiftRightJam64( frac64, 18 ); if ( ! (exp | frac32) ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ exp -= 0x3F81; if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF32( sign, exp, frac32 | 0x40000000 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t softfloat_normRoundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig ) { int_fast8_t shiftDist; union ui32_f32 uZ; shiftDist = softfloat_countLeadingZeros32( sig ) - 1; exp -= shiftDist; if ( (7 <= shiftDist) && ((unsigned int) exp < 0xFD) ) { uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<(shiftDist - 7) ); return uZ.f; } else { return softfloat_roundPackToF32( sign, exp, sig<<shiftDist ); } }
float32_t ui32_to_f32( uint_fast32_t a ) { union ui32_f32 uZ; if ( ! a ) { uZ.ui = 0; return uZ.f; } if ( a & 0x80000000 ) { return softfloat_roundPackToF32( 0, 0x9D, softfloat_shortShift32Right1Jam( a ) ); } else { return softfloat_normRoundPackToF32( 0, 0x9C, a ); } }
float32_t extF80_to_f32( extFloat80_t a ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64; uint_fast64_t uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig; struct commonNaN commonNaN; uint_fast32_t uiZ, sig32; union ui32_f32 uZ; uA.f = a; uiA64 = uA.s.signExp; uiA0 = uA.s.signif; sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uiA0; if ( exp == 0x7FFF ) { if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } sig32 = softfloat_shortShiftRightJam64( sig, 33 ); if ( ! (exp | sig32) ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } exp -= 0x3F81; if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF32( sign, exp, sig32 ); uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t f32_div( float32_t a, float32_t b ) { union ui32_f32 uA; uint_fast32_t uiA; bool signA; int_fast16_t expA; uint_fast32_t sigA; union ui32_f32 uB; uint_fast32_t uiB; bool signB; int_fast16_t expB; uint_fast32_t sigB; bool signZ; struct exp16_sig32 normExpSig; int_fast16_t expZ; #ifdef SOFTFLOAT_FAST_DIV64TO32 uint_fast64_t sig64A; uint_fast32_t sigZ; #else uint_fast32_t sigZ; uint_fast64_t rem; #endif uint_fast32_t uiZ; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF32UI( uiA ); expA = expF32UI( uiA ); sigA = fracF32UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF32UI( uiB ); expB = expF32UI( uiB ); sigB = fracF32UI( uiB ); signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0xFF ) { if ( sigA ) goto propagateNaN; if ( expB == 0xFF ) { if ( sigB ) goto propagateNaN; goto invalid; } goto infinity; } if ( expB == 0xFF ) { if ( sigB ) goto propagateNaN; goto zero; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expB ) { if ( ! sigB ) { if ( ! (expA | sigA) ) goto invalid; softfloat_raiseFlags( softfloat_flag_infinite ); goto infinity; } normExpSig = softfloat_normSubnormalF32Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF32Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA - expB + 0x7E; sigA |= 0x00800000; sigB |= 0x00800000; #ifdef SOFTFLOAT_FAST_DIV64TO32 if ( sigA < sigB ) { --expZ; sig64A = (uint_fast64_t) sigA<<31; } else { sig64A = (uint_fast64_t) sigA<<30; } sigZ = sig64A / sigB; if ( ! (sigZ & 0x3F) ) sigZ |= ((uint_fast64_t) sigB * sigZ != sig64A); #else if ( sigA < sigB ) { --expZ; sigA <<= 8; } else { sigA <<= 7; } sigB <<= 8; sigZ = ((uint_fast64_t) sigA * softfloat_approxRecip32_1( sigB ))>>32; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sigZ += 2; if ( (sigZ & 0x3F) < 2 ) { sigZ &= ~3; #ifdef SOFTFLOAT_FAST_INT64 rem = ((uint_fast64_t) sigA<<31) - (uint_fast64_t) sigZ * sigB; #else rem = ((uint_fast64_t) sigA<<32) - (uint_fast64_t) (sigZ<<1) * sigB; #endif if ( rem & UINT64_C( 0x8000000000000000 ) ) { sigZ -= 4; } else { if ( rem ) sigZ |= 1; } } #endif return softfloat_roundPackToF32( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infinity: uiZ = packToF32UI( signZ, 0xFF, 0 ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ = packToF32UI( signZ, 0, 0 ); uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t f32_mul( float32_t a, float32_t b ) { union ui32_f32 uA; uint_fast32_t uiA; bool signA; int_fast16_t expA; uint_fast32_t sigA; union ui32_f32 uB; uint_fast32_t uiB; bool signB; int_fast16_t expB; uint_fast32_t sigB; bool signZ; uint_fast32_t magBits; struct exp16_sig32 normExpSig; int_fast16_t expZ; uint_fast32_t sigZ, uiZ; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF32UI( uiA ); expA = expF32UI( uiA ); sigA = fracF32UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF32UI( uiB ); expB = expF32UI( uiB ); sigB = fracF32UI( uiB ); signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0xFF ) { if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN; magBits = expB | sigB; goto infArg; } if ( expB == 0xFF ) { if ( sigB ) goto propagateNaN; magBits = expA | sigA; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF32Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalF32Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x7F; sigA = (sigA | 0x00800000)<<7; sigB = (sigB | 0x00800000)<<8; sigZ = softfloat_shortShiftRightJam64( (uint_fast64_t) sigA * sigB, 32 ); if ( sigZ < 0x40000000 ) { --expZ; sigZ <<= 1; } return softfloat_roundPackToF32( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; } else { uiZ = packToF32UI( signZ, 0xFF, 0 ); } goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ = packToF32UI( signZ, 0, 0 ); uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t softfloat_addMagsF32( uint_fast32_t uiA, uint_fast32_t uiB, bool signZ ) { int_fast16_t expA; uint_fast32_t sigA; int_fast16_t expB; uint_fast32_t sigB; int_fast16_t expDiff; uint_fast32_t uiZ; int_fast16_t expZ; uint_fast32_t sigZ; union ui32_f32 uZ; expA = expF32UI( uiA ); sigA = fracF32UI( uiA ); expB = expF32UI( uiB ); sigB = fracF32UI( uiB ); expDiff = expA - expB; sigA <<= 6; sigB <<= 6; if ( ! expDiff ) { if ( expA == 0xFF ) { if ( sigA | sigB ) goto propagateNaN; uiZ = uiA; goto uiZ; } if ( ! expA ) { uiZ = packToF32UI( signZ, 0, (uiA + uiB) & 0x7FFFFFFF ); goto uiZ; } expZ = expA; sigZ = 0x40000000 + sigA + sigB; } else { if ( expDiff < 0 ) { if ( expB == 0xFF ) { if ( sigB ) goto propagateNaN; uiZ = packToF32UI( signZ, 0xFF, 0 ); goto uiZ; } expZ = expB; sigA += expA ? 0x20000000 : sigA; sigA = softfloat_shiftRightJam32( sigA, -expDiff ); } else { if ( expA == 0xFF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } expZ = expA; sigB += expB ? 0x20000000 : sigB; sigB = softfloat_shiftRightJam32( sigB, expDiff ); } sigZ = 0x20000000 + sigA + sigB; if ( sigZ < 0x40000000 ) { --expZ; sigZ <<= 1; } } return softfloat_roundPackToF32( signZ, expZ, sigZ ); propagateNaN: uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t softfloat_mulAddF32( int op, uint_fast32_t uiA, uint_fast32_t uiB, uint_fast32_t uiC ) { 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 sigZ64, sigC64; int 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_shortShift64RightJam( 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_shift64RightJam( sigProd, 32 - expDiff ); } else { expZ = expProd; sigZ64 = sigProd + softfloat_shift64RightJam( (uint_fast64_t) sigC<<32, expDiff ); sigZ = softfloat_shortShift64RightJam( sigZ64, 32 ); } if ( sigZ < 0x40000000 ) { --expZ; sigZ <<= 1; } } else { /*** OPTIMIZE BETTER? ***/ sigC64 = (uint_fast64_t) sigC<<32; if ( expDiff < 0 ) { signZ = signC; expZ = expC; sigZ64 = sigC64 - softfloat_shift64RightJam( sigProd, - expDiff ); } else if ( ! expDiff ) { expZ = expProd; sigZ64 = sigProd - sigC64; if ( ! sigZ64 ) goto completeCancellation; if ( sigZ64 & UINT64_C( 0x8000000000000000 ) ) { signZ ^= 1; sigZ64 = - sigZ64; } } else { expZ = expProd; sigZ64 = sigProd - softfloat_shift64RightJam( sigC64, expDiff ); } shiftCount = softfloat_countLeadingZeros64( sigZ64 ) - 1; expZ -= shiftCount; shiftCount -= 32; if ( shiftCount < 0 ) { sigZ = softfloat_shortShift64RightJam( sigZ64, - shiftCount ); } else { sigZ = (uint_fast32_t) sigZ64<<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; }