float64_t f64_roundToInt( float64_t a, uint_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t uiZ, lastBitMask, roundBitsMask; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp <= 0x3FE ) { if ( !(uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) return a; if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; uiZ = uiA & packToF64UI( 1, 0, 0 ); switch ( roundingMode ) { case softfloat_round_near_even: if ( !fracF64UI( uiA ) ) break; case softfloat_round_near_maxMag: if ( exp == 0x3FE ) uiZ |= packToF64UI( 0, 0x3FF, 0 ); break; case softfloat_round_min: if ( uiZ ) uiZ = packToF64UI( 1, 0x3FF, 0 ); break; case softfloat_round_max: if ( !uiZ ) uiZ = packToF64UI( 0, 0x3FF, 0 ); break; #ifdef SOFTFLOAT_ROUND_ODD case softfloat_round_odd: uiZ |= packToF64UI( 0, 0x3FF, 0 ); break; #endif } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x433 <= exp ) { if ( (exp == 0x7FF) && fracF64UI( uiA ) ) { uiZ = softfloat_propagateNaNF64UI( uiA, 0 ); goto uiZ; } return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = uiA; lastBitMask = (uint_fast64_t) 1<<(0x433 - exp); roundBitsMask = lastBitMask - 1; if ( roundingMode == softfloat_round_near_maxMag ) { uiZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_near_even ) {
float64_t f128_to_f64( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t frac64, frac0; struct commonNaN commonNaN; uint_fast64_t uiZ; struct uint128 frac128; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); frac64 = fracF128UI64( uiA64 ); frac0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( frac64 | frac0 ) { softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF64UI( &commonNaN ); } else { uiZ = packToF64UI( sign, 0x7FF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac128 = softfloat_shortShiftLeft128( frac64, frac0, 14 ); frac64 = frac128.v64 | (frac128.v0 != 0); if ( ! (exp | frac64) ) { uiZ = packToF64UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ exp -= 0x3C01; if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF64( sign, exp, frac64 | UINT64_C( 0x4000000000000000 ) ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; }
float64_t extF80M_to_f64( const extFloat80_t *aPtr ) { const struct extFloat80M *aSPtr; uint_fast16_t uiA64; bool sign; int32_t exp; uint64_t sig; struct commonNaN commonNaN; uint64_t uiZ; union ui64_f64 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_commonNaNToF64UI( &commonNaN ); } else { uiZ = packToF64UI( sign, 0x7FF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! (sig & UINT64_C( 0x8000000000000000 )) ) { if ( ! sig ) { uiZ = packToF64UI( sign, 0, 0 ); goto uiZ; } exp += softfloat_normExtF80SigM( &sig ); } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig = softfloat_shortShiftRightJam64( sig, 1 ); exp -= 0x3C01; if ( sizeof (int_fast16_t) < sizeof (int32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF64( sign, exp, sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; }
float64_t f64_roundToInt( float64_t a, int_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t expA; uint_fast64_t uiZ; bool signA; uint_fast64_t lastBitMask, roundBitsMask; union ui64_f64 uZ; uA.f = a; uiA = uA.ui; expA = expF64UI( uiA ); if ( 0x433 <= expA ) { if ( ( expA == 0x7FF ) && fracF64UI( uiA ) ) { uiZ = softfloat_propagateNaNF64UI( uiA, 0 ); goto uiZ; } return a; } if ( expA <= 0x3FE ) { if ( ! ( uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) ) return a; if ( exact ) softfloat_raiseFlags( softfloat_flag_inexact ); signA = signF64UI( uiA ); switch ( roundingMode ) { case softfloat_round_nearest_even: if ( ( expA == 0x3FE ) && fracF64UI( uiA ) ) { uiZ = packToF64UI( signA, 0x3FF, 0 ); goto uiZ; } break; case softfloat_round_min: uiZ = signA ? UINT64_C( 0xBFF0000000000000 ) : 0; goto uiZ; case softfloat_round_max: uiZ = signA ? UINT64_C( 0x8000000000000000 ) : UINT64_C( 0x3FF0000000000000 ); goto uiZ; case softfloat_round_nearest_maxMag: if ( expA == 0x3FE ) { uiZ = packToF64UI( signA, 0x3FF, 0 ); goto uiZ; } break; } uiZ = packToF64UI( signA, 0, 0 ); goto uiZ; } lastBitMask = (uint_fast64_t) 1<<( 0x433 - expA ); roundBitsMask = lastBitMask - 1; uiZ = uiA; if ( roundingMode == softfloat_round_nearest_maxMag ) { uiZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_nearest_even ) {
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; }
float64_t extF80_to_f64( 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_fast64_t uiZ; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.s.signExp; uiA0 = uA.s.signif; sign = signExtF80UI64( uiA64 ); exp = expExtF80UI64( uiA64 ); sig = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! (exp | sig) ) { uiZ = packToF64UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { softfloat_extF80UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF64UI( &commonNaN ); } else { uiZ = packToF64UI( sign, 0x7FF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig = softfloat_shortShiftRightJam64( sig, 1 ); exp -= 0x3C01; if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF64( sign, exp, sig ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; }
float64_t f16_to_f64( 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_fast64_t uiZ; struct exp8_sig16 normExpSig; union ui64_f64 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_commonNaNToF64UI( &commonNaN ); } else { uiZ = packToF64UI( sign, 0x7FF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ = packToF64UI( sign, 0, 0 ); goto uiZ; } normExpSig = softfloat_normSubnormalF16Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = packToF64UI( sign, exp + 0x3F0, (uint_fast64_t) frac<<42 ); uiZ: uZ.ui = uiZ; return uZ.f; }
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; }
float64_t i64_to_f64( int64_t a ) { bool sign; union ui64_f64 uZ; uint_fast64_t absA; sign = (a < 0); if ( ! (a & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { uZ.ui = sign ? packToF64UI( 1, 0x43E, 0 ) : 0; return uZ.f; } absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; return softfloat_normRoundPackToF64( sign, 0x43C, absA ); }
float64_t softfloat_normRoundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig ) { int_fast8_t shiftCount; union ui64_f64 uZ; shiftCount = softfloat_countLeadingZeros64( sig ) - 1; exp -= shiftCount; if ( (10 <= shiftCount) && ((uint16_t) exp < 0x7FD) ) { uZ.ui = packToF64UI( sign, sig ? exp : 0, sig<<(shiftCount - 10) ); return uZ.f; } else { return softfloat_roundPackToF64( sign, exp, sig<<shiftCount ); } }
float64_t ui32_to_f64( uint32_t a ) { uint_fast64_t uiZ; int_fast8_t shiftDist; union ui64_f64 uZ; if ( ! a ) { uiZ = 0; } else { shiftDist = softfloat_countLeadingZeros32( a ) + 21; uiZ = packToF64UI( 0, 0x432 - shiftDist, (uint_fast64_t) a<<shiftDist ); } uZ.ui = uiZ; return uZ.f; }
int_fast64_t f64_to_i64_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; int_fast64_t absZ; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); shiftCount = 0x433 - exp; if ( shiftCount <= 0 ) { if ( shiftCount < -10 ) { if ( uiA != packToF64UI( 1, 0x43E, 0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); if ( ! sign || ((exp == 0x7FF) && sig) ) { return INT64_C( 0x7FFFFFFFFFFFFFFF ); } } return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } sig |= UINT64_C( 0x0010000000000000 ); absZ = sig<<-shiftCount; } else { if ( 53 <= shiftCount ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } sig |= UINT64_C( 0x0010000000000000 ); absZ = sig>>shiftCount; if ( exact && (absZ<<shiftCount != sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } } return sign ? -absZ : absZ; }
float64_t i32_to_f64( int32_t a ) { uint_fast64_t uiZ; bool sign; uint_fast32_t absA; int_fast8_t shiftDist; union ui64_f64 uZ; if ( ! a ) { uiZ = 0; } else { sign = (a < 0); absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; shiftDist = softfloat_countLeadingZeros32( absA ) + 21; uiZ = packToF64UI( sign, 0x432 - shiftDist, (uint_fast64_t) absA<<shiftDist ); } 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_shift64RightJam( sigA, - expDiff ); } else { if ( expA == 0x7FF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } expZ = expA; sigB += expB ? UINT64_C( 0x2000000000000000 ) : sigB; sigB = softfloat_shift64RightJam( 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; 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; }
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 f64_mul( float64_t a, float64_t b ) { union ui64_f64 uA; uint_fast64_t uiA; bool signA; int_fast16_t expA; uint_fast64_t sigA; union ui64_f64 uB; uint_fast64_t uiB; bool signB; int_fast16_t expB; uint_fast64_t sigB; bool signZ; uint_fast64_t magBits; struct exp16_sig64 normExpSig; int_fast16_t expZ; #ifdef SOFTFLOAT_FAST_INT64 struct uint128 sig128Z; #else uint32_t sig128Z[4]; #endif uint_fast64_t sigZ, uiZ; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF64UI( uiA ); expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF64UI( uiB ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FF ) { if ( sigA || ((expB == 0x7FF) && sigB) ) goto propagateNaN; magBits = expB | sigB; goto infArg; } if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; magBits = expA | sigA; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF64Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalF64Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FF; sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<11; #ifdef SOFTFLOAT_FAST_INT64 sig128Z = softfloat_mul64To128( sigA, sigB ); sigZ = sig128Z.v64 | (sig128Z.v0 != 0); #else softfloat_mul64To128M( sigA, sigB, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) sigZ |= 1; #endif if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { --expZ; sigZ <<= 1; } return softfloat_roundPackToF64( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; } else { uiZ = packToF64UI( signZ, 0x7FF, 0 ); } goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ = packToF64UI( signZ, 0, 0 ); uiZ: uZ.ui = uiZ; return uZ.f; }
float64_t f64_mul( float64_t a, float64_t b ) { union ui64_f64 uA; uint_fast64_t uiA; bool signA; int_fast16_t expA; uint_fast64_t sigA; union ui64_f64 uB; uint_fast64_t uiB; bool signB; int_fast16_t expB; uint_fast64_t sigB; bool signZ; uint_fast64_t magBits; struct exp16_sig64 normExpSig; int_fast16_t expZ; struct uint128 sigZ128; uint_fast64_t sigZ, uiZ; union ui64_f64 uZ; uA.f = a; uiA = uA.ui; signA = signF64UI( uiA ); expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF64UI( uiB ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); signZ = signA ^ signB; if ( expA == 0x7FF ) { if ( sigA || ( ( expB == 0x7FF ) && sigB ) ) goto propagateNaN; magBits = expB | sigB; goto infArg; } if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; magBits = expA | sigA; goto infArg; } if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF64Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalF64Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } expZ = expA + expB - 0x3FF; sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<10; sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<11; sigZ128 = softfloat_mul64To128( sigA, sigB ); sigZ = sigZ128.v64 | ( sigZ128.v0 != 0 ); if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { --expZ; sigZ <<= 1; } return softfloat_roundPackToF64( signZ, expZ, sigZ ); propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); goto uiZ; infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; } else { uiZ = packToF64UI( signZ, 0x7FF, 0 ); } goto uiZ; zero: uiZ = packToF64UI( signZ, 0, 0 ); 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; }