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 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 f32_roundToInt( float32_t a, int_fast8_t roundingMode, bool exact ) { union ui32_f32 uA; uint_fast32_t uiA; int_fast16_t expA; uint_fast32_t uiZ; bool signA; uint_fast32_t lastBitMask, roundBitsMask; union ui32_f32 uZ; uA.f = a; uiA = uA.ui; expA = expF32UI( uiA ); if ( 0x96 <= expA ) { if ( ( expA == 0xFF ) && fracF32UI( uiA ) ) { uiZ = softfloat_propagateNaNF32UI( uiA, 0 ); goto uiZ; } return a; } if ( expA <= 0x7E ) { if ( ! (uint32_t) ( uiA<<1 ) ) return a; if ( exact ) softfloat_raiseFlags( softfloat_flag_inexact ); signA = signF32UI( uiA ); switch ( roundingMode ) { case softfloat_round_nearest_even: if ( ( expA == 0x7E ) && fracF32UI( uiA ) ) { uiZ = packToF32UI( signA, 0x7F, 0 ); goto uiZ; } break; case softfloat_round_min: uiZ = signA ? 0xBF800000 : 0; goto uiZ; case softfloat_round_max: uiZ = signA ? 0x80000000 : 0x3F800000; goto uiZ; case softfloat_round_nearest_maxMag: if ( expA == 0x7E ) { uiZ = packToF32UI( signA, 0x7F, 0 ); goto uiZ; } break; } uiZ = packToF32UI( signA, 0, 0 ); goto uiZ; } lastBitMask = (uint_fast32_t) 1<<( 0x96 - expA ); roundBitsMask = lastBitMask - 1; uiZ = uiA; if ( roundingMode == softfloat_round_nearest_maxMag ) { uiZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_nearest_even ) {
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 f32_roundToInt( float32_t a, uint_fast8_t roundingMode, bool exact ) { union ui32_f32 uA; uint_fast32_t uiA; int_fast16_t exp; uint_fast32_t uiZ, lastBitMask, roundBitsMask; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp <= 0x7E ) { if ( ! (uint32_t) (uiA<<1) ) return a; if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; uiZ = uiA & packToF32UI( 1, 0, 0 ); switch ( roundingMode ) { case softfloat_round_near_even: if ( ! fracF32UI( uiA ) ) break; case softfloat_round_near_maxMag: if ( exp == 0x7E ) uiZ |= packToF32UI( 0, 0x7F, 0 ); break; case softfloat_round_min: if ( uiZ ) uiZ = packToF32UI( 1, 0x7F, 0 ); break; case softfloat_round_max: if ( ! uiZ ) uiZ = packToF32UI( 0, 0x7F, 0 ); break; } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x96 <= exp ) { if ( (exp == 0xFF) && fracF32UI( uiA ) ) { uiZ = softfloat_propagateNaNF32UI( uiA, 0 ); goto uiZ; } return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = uiA; lastBitMask = (uint_fast32_t) 1<<(0x96 - exp); roundBitsMask = lastBitMask - 1; if ( roundingMode == softfloat_round_near_maxMag ) { uiZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_near_even ) {
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_roundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig ) { uint_fast8_t roundingMode; bool roundNearEven; uint_fast8_t roundIncrement, roundBits; bool isTiny; uint_fast32_t uiZ; union ui32_f32 uZ; roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x40; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0x7F : 0; } roundBits = sig & 0x7F; if ( 0xFD <= (uint16_t) exp ) { if ( exp < 0 ) { isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < -1) || (sig + roundIncrement < 0x80000000); sig = softfloat_shiftRightJam32( sig, -exp ); exp = 0; roundBits = sig & 0x7F; if ( isTiny && roundBits ) { softfloat_raiseFlags( softfloat_flag_underflow ); } } else if ( (0xFD < exp) || (0x80000000 <= sig + roundIncrement) ) { softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); uiZ = packToF32UI( sign, 0xFF, 0 ) - ! roundIncrement; goto uiZ; } } if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact; sig = (sig + roundIncrement)>>7; sig &= ~(uint_fast32_t) (! (roundBits ^ 0x40) & roundNearEven); uiZ = packToF32UI( sign, sig ? exp : 0, sig ); uiZ: uZ.ui = uiZ; return uZ.f; }
float32_t f16_to_f32( float16_t a ) { union ui16_f16 uA; uint_fast16_t uiA; bool sign; int_fast8_t exp; uint_fast16_t frac; struct commonNaN commonNaN; uint_fast32_t uiZ; struct exp8_sig16 normExpSig; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF16UI( uiA ); exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x1F ) { if ( frac ) { softfloat_f16UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } normExpSig = softfloat_normSubnormalF16Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = packToF32UI( sign, exp + 0x70, (uint_fast32_t) frac<<13 ); 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 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; }
int_fast64_t f32_to_i64_r_minMag( float32_t a, bool exact ) { union ui32_f32 uA; uint_fast32_t uiA; int_fast16_t exp; uint_fast32_t sig; int_fast16_t shiftDist; bool sign; uint_fast64_t sig64; int_fast64_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0xBE - exp; if ( 64 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF32UI( uiA ); if ( shiftDist <= 0 ) { if ( uiA == packToF32UI( 1, 0xBE, 0 ) ) { return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<40; absZ = sig64>>shiftDist; shiftDist = 40 - shiftDist; if ( exact && (shiftDist < 0) && (uint32_t) (sig<<(shiftDist & 31)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sign ? -absZ : absZ; }
float32_t i32_to_f32( int32_t a ) { bool sign; union ui32_f32 uZ; uint_fast32_t absA; sign = (a < 0); if ( ! (a & 0x7FFFFFFF) ) { uZ.ui = sign ? packToF32UI( 1, 0x9E, 0 ) : 0; return uZ.f; } absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; return softfloat_normRoundPackToF32( sign, 0x9C, absA ); }
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 ); } }
int_fast64_t f32_to_i64_r_minMag( float32_t a, bool exact ) { union ui32_f32 uA; uint_fast32_t uiA; int_fast16_t exp; uint_fast32_t sig; int_fast16_t shiftCount; bool sign; uint_fast64_t sig64; int_fast64_t absZ; uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); sig = fracF32UI( uiA ); shiftCount = 0xBE - exp; if ( 64 <= shiftCount ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } sign = signF32UI( uiA ); if ( shiftCount <= 0 ) { if ( uiA != packToF32UI( 1, 0xBE, 0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); if ( ! sign || ((exp == 0xFF) && sig) ) { return INT64_C( 0x7FFFFFFFFFFFFFFF ); } } return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<40; absZ = sig64>>shiftCount; shiftCount = 40 - shiftCount; if ( exact && (shiftCount < 0) && (uint32_t) (sig<<(shiftCount & 31)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sign ? -absZ : absZ; }
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; }
float32_t softfloat_subMagsF32( 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 <<= 7; sigB <<= 7; if ( 0 < expDiff ) goto expABigger; if ( expDiff < 0 ) goto expBBigger; if ( expA == 0xFF ) { if ( sigA | sigB ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; goto uiZ; } if ( ! expA ) { expA = 1; expB = 1; } if ( sigB < sigA ) goto aBigger; if ( sigA < sigB ) goto bBigger; uiZ = packToF32UI( softfloat_roundingMode == softfloat_round_min, 0, 0 ); goto uiZ; expBBigger: if ( expB == 0xFF ) { if ( sigB ) goto propagateNaN; uiZ = packToF32UI( signZ ^ 1, 0xFF, 0 ); goto uiZ; } sigA += expA ? 0x40000000 : sigA; sigA = softfloat_shift32RightJam( sigA, - expDiff ); sigB |= 0x40000000; bBigger: signZ ^= 1; expZ = expB; sigZ = sigB - sigA; goto normRoundPack; expABigger: if ( expA == 0xFF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } sigB += expB ? 0x40000000 : sigB; sigB = softfloat_shift32RightJam( sigB, expDiff ); sigA |= 0x40000000; aBigger: expZ = expA; sigZ = sigA - sigB; normRoundPack: return softfloat_normRoundPackToF32( signZ, expZ - 1, sigZ ); propagateNaN: uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); 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 softfloat_subMagsF32( uint_fast32_t uiA, uint_fast32_t uiB ) { 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_fast32_t sigDiff; bool signZ; int_fast8_t shiftDist; int_fast16_t expZ; uint_fast32_t sigX, sigY; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expA = expF32UI( uiA ); sigA = fracF32UI( uiA ); expB = expF32UI( uiB ); sigB = fracF32UI( uiB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; if ( ! expDiff ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expA == 0xFF ) { if ( sigA | sigB ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; goto uiZ; } sigDiff = sigA - sigB; if ( ! sigDiff ) { uiZ = packToF32UI( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); goto uiZ; } if ( expA ) --expA; signZ = signF32UI( uiA ); if ( sigDiff < 0 ) { signZ = ! signZ; sigDiff = -sigDiff; } shiftDist = softfloat_countLeadingZeros32( sigDiff ) - 8; expZ = expA - shiftDist; if ( expZ < 0 ) { shiftDist = expA; expZ = 0; } uiZ = packToF32UI( signZ, expZ, sigDiff<<shiftDist ); goto uiZ; } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ signZ = signF32UI( uiA ); sigA <<= 7; sigB <<= 7; if ( expDiff < 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ signZ = ! signZ; if ( expB == 0xFF ) { if ( sigB ) goto propagateNaN; uiZ = packToF32UI( signZ, 0xFF, 0 ); goto uiZ; } expZ = expB - 1; sigX = sigB | 0x40000000; sigY = sigA + (expA ? 0x40000000 : sigA); expDiff = -expDiff; } else { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ if ( expA == 0xFF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } expZ = expA - 1; sigX = sigA | 0x40000000; sigY = sigB + (expB ? 0x40000000 : sigB); } return softfloat_normRoundPackToF32( signZ, expZ, sigX - softfloat_shiftRightJam32( sigY, expDiff ) ); } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); 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; }