bool f32_le( float32_t a, float32_t b ) { union ui32_f32 uA; uint_fast32_t uiA; union ui32_f32 uB; uint_fast32_t uiB; bool signA, signB; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; if ( ( ( expF32UI( uiA ) == 0xFF ) && fracF32UI( uiA ) ) || ( ( expF32UI( uiB ) == 0xFF ) && fracF32UI( uiB ) ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } signA = signF32UI( uiA ); signB = signF32UI( uiB ); return ( signA != signB ) ? signA || ! (uint32_t) ( ( uiA | uiB )<<1 ) : ( uiA == uiB ) || ( signA ^ ( uiA < uiB ) ); }
bool f32_eq( float32_t a, float32_t b ) { union ui32_f32 uA; uint_fast32_t uiA; union ui32_f32 uB; uint_fast32_t uiB; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; if ( ( ( expF32UI( uiA ) == 0xFF ) && fracF32UI( uiA ) ) || ( ( expF32UI( uiB ) == 0xFF ) && fracF32UI( uiB ) ) ) { if ( softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } return ( uiA == uiB ) || ! (uint32_t) ( ( uiA | uiB )<<1 ); }
uint_fast64_t f32_to_ui64_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; uint_fast64_t sig64, z; 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; } if ( signF32UI( uiA ) || (shiftCount < 0) ) goto invalid; sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<40; z = sig64>>shiftCount; shiftCount = 40 - shiftCount; if ( exact && (shiftCount < 0) && (uint32_t) (sig<<(shiftCount & 31)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return UINT64_C( 0xFFFFFFFFFFFFFFFF ); }
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 ); }
int_fast64_t f32_to_i64( float32_t a, int_fast8_t roundingMode, bool exact ) { union ui32_f32 uA; uint_fast32_t uiA; bool sign; int_fast16_t exp; uint_fast32_t sig; int_fast16_t shiftCount; uint_fast64_t sig64, extra; struct uint64_extra sig64Extra; uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); sig = fracF32UI( uiA ); shiftCount = 0xBE - exp; if ( shiftCount < 0 ) { softfloat_raiseFlags( softfloat_flag_invalid ); if ( ! sign || ( ( exp == 0xFF ) && sig ) ) { return INT64_C( 0x7FFFFFFFFFFFFFFF ); } return - INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } if ( exp ) sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<40; extra = 0; if ( shiftCount ) { sig64Extra = softfloat_shift64ExtraRightJam( sig64, 0, shiftCount ); sig64 = sig64Extra.v; extra = sig64Extra.extra; } return softfloat_roundPackToI64( sign, sig64, extra, roundingMode, exact ); }
extFloat80_t f32_to_extF80( float32_t a ) { union ui32_f32 uA; uint_fast32_t uiA; bool sign; int_fast16_t exp; uint_fast32_t frac; struct commonNaN commonNaN; struct uint128 uiZ; uint_fast16_t uiZ64; uint_fast64_t uiZ0; struct exp16_sig32 normExpSig; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); frac = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0xFF ) { if ( frac ) { softfloat_f32UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToExtF80UI( &commonNaN ); uiZ64 = uiZ.v64; uiZ0 = uiZ.v0; } else { uiZ64 = packToExtF80UI64( sign, 0x7FFF ); uiZ0 = UINT64_C( 0x8000000000000000 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ64 = packToExtF80UI64( sign, 0 ); uiZ0 = 0; goto uiZ; } normExpSig = softfloat_normSubnormalF32Sig( frac ); exp = normExpSig.exp; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ64 = packToExtF80UI64( sign, exp + 0x3F80 ); uiZ0 = (uint_fast64_t) (frac | 0x00800000)<<40; uiZ: uZ.s.signExp = uiZ64; uZ.s.signif = uiZ0; 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 ) {
float128_t f32_to_f128( float32_t a ) { union ui32_f32 uA; uint_fast32_t uiA; bool sign; int_fast16_t exp; uint_fast32_t frac; struct commonNaN commonNaN; struct uint128 uiZ; struct exp16_sig32 normExpSig; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); frac = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0xFF ) { if ( frac ) { softfloat_f32UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF128UI( &commonNaN ); } else { uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); uiZ.v0 = 0; } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ.v64 = packToF128UI64( sign, 0, 0 ); uiZ.v0 = 0; goto uiZ; } normExpSig = softfloat_normSubnormalF32Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ.v64 = packToF128UI64( sign, exp + 0x3F80, (uint_fast64_t) frac<<25 ); uiZ.v0 = 0; uiZ: uZ.ui = uiZ; return uZ.f; }
int_fast64_t f32_to_i64( 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; int_fast16_t shiftDist; #ifdef SOFTFLOAT_FAST_INT64 uint_fast64_t sig64, extra; struct uint64_extra sig64Extra; #else uint32_t extSig[3]; #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0xBE - exp; if ( shiftDist < 0 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= 0x00800000; #ifdef SOFTFLOAT_FAST_INT64 sig64 = (uint_fast64_t) sig<<40; extra = 0; if ( shiftDist ) { sig64Extra = softfloat_shiftRightJam64Extra( sig64, 0, shiftDist ); sig64 = sig64Extra.v; extra = sig64Extra.extra; } return softfloat_roundToI64( sign, sig64, extra, roundingMode, exact ); #else extSig[indexWord( 3, 2 )] = sig<<8; extSig[indexWord( 3, 1 )] = 0; extSig[indexWord( 3, 0 )] = 0; if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); #endif }
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 ) {
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; }
float16_t f32_to_f16( float32_t a ) { union ui32_f32 uA; uint_fast32_t uiA; bool sign; int_fast16_t exp; uint_fast32_t frac; struct commonNaN commonNaN; uint_fast16_t uiZ, frac16; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); frac = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0xFF ) { if ( frac ) { softfloat_f32UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF16UI( &commonNaN ); } else { uiZ = packToF16UI( sign, 0x1F, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac16 = frac>>9 | ((frac & 0x1FF) != 0); if ( ! (exp | frac16) ) { uiZ = packToF16UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ return softfloat_roundPackToF16( sign, exp - 0x71, frac16 | 0x4000 ); uiZ: uZ.ui = uiZ; return uZ.f; }
uint_fast32_t f32_to_ui32_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_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x9E - exp; if ( 32 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF32UI( uiA ); if ( sign || (shiftDist < 0) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? ui32_fromNaN : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig = (sig | 0x00800000)<<8; z = sig>>shiftDist; if ( exact && (z<<shiftDist != sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; }
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; }
float64_t f32_to_f64( float32_t a ) { union ui32_f32 uA; uint_fast32_t uiA; bool sign; int_fast16_t exp; uint_fast32_t sig; uint_fast64_t uiZ; struct exp16_sig32 normExpSig; union ui64_f64 uZ; uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); sig = fracF32UI( uiA ); if ( exp == 0xFF ) { uiZ = sig ? softfloat_commonNaNToF64UI( softfloat_f32UIToCommonNaN( uiA ) ) : packToF64UI( sign, 0x7FF, 0 ); goto uiZ; } if ( ! exp ) { if ( ! sig ) { uiZ = packToF64UI( sign, 0, 0 ); goto uiZ; } normExpSig = softfloat_normSubnormalF32Sig( sig ); exp = normExpSig.exp - 1; sig = normExpSig.sig; } uiZ = packToF64UI( sign, exp + 0x380, (uint_fast64_t) sig<<29 ); 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; }
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_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_rem( 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; int_fast16_t expB; uint_fast32_t sigB; struct exp16_sig32 normExpSig; uint32_t rem; int_fast16_t expDiff; uint32_t q, recip32, altRem, meanRem; bool signRem; 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; expB = expF32UI( uiB ); sigB = fracF32UI( uiB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0xFF ) { if ( sigA || ((expB == 0xFF) && sigB) ) goto propagateNaN; goto invalid; } if ( expB == 0xFF ) { if ( sigB ) goto propagateNaN; return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expB ) { if ( ! sigB ) goto invalid; normExpSig = softfloat_normSubnormalF32Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } if ( ! expA ) { if ( ! sigA ) return a; normExpSig = softfloat_normSubnormalF32Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ rem = sigA | 0x00800000; sigB |= 0x00800000; expDiff = expA - expB; if ( expDiff < 1 ) { if ( expDiff < -1 ) return a; sigB <<= 6; if ( expDiff ) { rem <<= 5; q = 0; } else { rem <<= 6; q = (sigB <= rem); if ( q ) rem -= sigB; } } else { recip32 = softfloat_approxRecip32_1( sigB<<8 ); /*-------------------------------------------------------------------- | Changing the shift of `rem' here requires also changing the initial | subtraction from `expDiff'. *--------------------------------------------------------------------*/ rem <<= 7; expDiff -= 31; /*-------------------------------------------------------------------- | The scale of `sigB' affects how many bits are obtained during each | cycle of the loop. Currently this is 29 bits per loop iteration, | which is believed to be the maximum possible. *--------------------------------------------------------------------*/ sigB <<= 6; for (;;) { q = (rem * (uint_fast64_t) recip32)>>32; if ( expDiff < 0 ) break; rem = -(q * (uint32_t) sigB); expDiff -= 29; } /*-------------------------------------------------------------------- | (`expDiff' cannot be less than -30 here.) *--------------------------------------------------------------------*/ q >>= ~expDiff & 31; rem = (rem<<(expDiff + 30)) - q * (uint32_t) sigB; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ do { altRem = rem; ++q; rem -= sigB; } while ( ! (rem & 0x80000000) ); meanRem = rem + altRem; if ( (meanRem & 0x80000000) || (! meanRem && (q & 1)) ) rem = altRem; signRem = signA; if ( 0x80000000 <= rem ) { signRem = ! signRem; rem = -rem; } return softfloat_normRoundPackToF32( signRem, expB, rem ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); goto uiZ; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; 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; }