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; }
extFloat80_t f128_to_extF80( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; struct commonNaN commonNaN; struct uint128 uiZ; uint_fast16_t uiZ64; uint_fast64_t uiZ0; struct exp32_sig128 normExpSig; struct uint128 sig128; union { struct extFloat80M s; extFloat80_t f; } uZ; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; if ( exp == 0x7FFF ) { if ( sig64 | sig0 ) { softfloat_f128UIToCommonNaN( uiA64, uiA0, &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 ( ! (sig64 | sig0) ) { uiZ64 = packToExtF80UI64( sign, 0 ); uiZ0 = 0; goto uiZ; } normExpSig = softfloat_normSubnormalF128Sig( sig64, sig0 ); exp = normExpSig.exp; sig64 = normExpSig.sig.v64; sig0 = normExpSig.sig.v0; } else { sig64 |= UINT64_C( 0x0001000000000000 ); } sig128 = softfloat_shortShiftLeft128( sig64, sig0, 15 ); return softfloat_roundPackToExtF80( sign, exp, sig128.v64, sig128.v0, 80 ); uiZ: uZ.s.signExp = uiZ64; uZ.s.signif = uiZ0; return uZ.f; }
void f64_to_extF80M( float64_t a, extFloat80_t *zPtr ) { struct extFloat80M *zSPtr; union ui64_f64 uA; uint64_t uiA; bool sign; int_fast16_t exp; uint64_t frac; struct commonNaN commonNaN; uint_fast16_t uiZ64; uint64_t uiZ0; struct exp16_sig64 normExpSig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zSPtr = (struct extFloat80M *) zPtr; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); frac = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FF ) { if ( frac ) { softfloat_f64UIToCommonNaN( uiA, &commonNaN ); softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); return; } uiZ64 = packToExtF80UI64( sign, 0x7FFF ); uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ64 = packToExtF80UI64( sign, 0 ); uiZ0 = 0; goto uiZ; } normExpSig = softfloat_normSubnormalF64Sig( frac ); exp = normExpSig.exp; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ64 = packToExtF80UI64( sign, exp + 0x3C00 ); uiZ0 = UINT64_C( 0x8000000000000000 ) | frac<<11; uiZ: zSPtr->signExp = uiZ64; zSPtr->signif = uiZ0; }
/*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into an 80-bit extended | floating-point NaN, and stores this NaN at the location pointed to by | `zSPtr'. *----------------------------------------------------------------------------*/ void softfloat_commonNaNToExtF80M( const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) { zSPtr->signExp = packToExtF80UI64( aPtr->sign, 0x7FFF ); zSPtr->signif = UINT64_C( 0xC000000000000000 ) | aPtr->v64>>1; }
void f128M_to_extF80M( const float128_t *aPtr, extFloat80_t *zPtr ) { const uint32_t *aWPtr; struct extFloat80M *zSPtr; uint32_t uiA96; bool sign; int32_t exp; struct commonNaN commonNaN; uint32_t sig[4]; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ aWPtr = (const uint32_t *) aPtr; zSPtr = (struct extFloat80M *) zPtr; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiA96 = aWPtr[indexWordHi( 4 )]; sign = signF128UI96( uiA96 ); exp = expF128UI96( uiA96 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( softfloat_isNaNF128M( aWPtr ) ) { softfloat_f128MToCommonNaN( aWPtr, &commonNaN ); softfloat_commonNaNToExtF80M( &commonNaN, zSPtr ); return; } zSPtr->signExp = packToExtF80UI64( sign, 0x7FFF ); zSPtr->signif = UINT64_C( 0x8000000000000000 ); return; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ exp = softfloat_shiftNormSigF128M( aWPtr, 15, sig ); if ( exp == -128 ) { zSPtr->signExp = packToExtF80UI64( sign, 0 ); zSPtr->signif = 0; return; } if ( sig[indexWord( 4, 0 )] ) sig[indexWord( 4, 1 )] |= 1; softfloat_roundPackMToExtF80M( sign, exp, &sig[indexMultiwordHi( 4, 3 )], 80, zSPtr ); }
int_fast32_t extF80_to_i32_r_minMag( extFloat80_t a, bool exact ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64; int_fast32_t exp; uint_fast64_t sig; int_fast32_t shiftDist; bool sign; int_fast32_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.s.signExp; exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x403E - exp; if ( 64 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signExtF80UI64( uiA64 ); if ( shiftDist < 33 ) { if ( (uiA64 == packToExtF80UI64( 1, 0x401E )) && (sig < UINT64_C( 0x8000000100000000 )) ) { if ( exact && (sig & UINT64_C( 0x00000000FFFFFFFF )) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return -0x7FFFFFFF - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ? i32_fromNaN : sign ? i32_fromNegOverflow : i32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ absZ = sig>>shiftDist; if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ<<shiftDist != sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sign ? -absZ : absZ; }
int_fast32_t extF80_to_i32_r_minMag( extFloat80_t a, bool exact ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64; int_fast32_t exp; uint_fast64_t sig; int_fast32_t shiftCount; bool sign; int_fast32_t absZ; uA.f = a; uiA64 = uA.s.signExp; exp = expExtF80UI64( uiA64 ); sig = uA.s.signif; shiftCount = 0x403E - exp; if ( 64 <= shiftCount ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } sign = signExtF80UI64( uiA64 ); if ( shiftCount < 33 ) { if ( (uiA64 == packToExtF80UI64( 1, 0x401E )) && (sig < UINT64_C( 0x8000000100000000 )) ) { if ( exact && (sig & UINT64_C( 0x00000000FFFFFFFF )) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } } else { softfloat_raiseFlags( softfloat_flag_invalid ); if ( ! sign || ((exp == 0x7FFF) && (sig & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) ) { return 0x7FFFFFFF; } } return -0x7FFFFFFF - 1; } absZ = sig>>shiftCount; if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ<<shiftCount != sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sign ? -absZ : absZ; }
void ui64_to_extF80M( uint64_t a, extFloat80_t *zPtr ) { struct extFloat80M *zSPtr; uint_fast16_t uiZ64; uint64_t sigZ; int_fast8_t shiftDist; zSPtr = (struct extFloat80M *) zPtr; uiZ64 = 0; sigZ = 0; if ( a ) { shiftDist = softfloat_countLeadingZeros64( a ); uiZ64 = packToExtF80UI64( 0, 0x403E - shiftDist ); sigZ = a<<shiftDist; } zSPtr->signExp = uiZ64; zSPtr->signif = sigZ; }
extFloat80_t i64_to_extF80( int64_t a ) { uint_fast16_t uiZ64; uint_fast64_t absA; bool sign; int_fast8_t shiftCount; union { struct extFloat80M s; extFloat80_t f; } uZ; uiZ64 = 0; absA = 0; if ( a ) { sign = (a < 0); absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; shiftCount = softfloat_countLeadingZeros64( absA ); uiZ64 = packToExtF80UI64( sign, 0x403E - shiftCount ); absA <<= shiftCount; } uZ.s.signExp = uiZ64; uZ.s.signif = absA; return uZ.f; }
void i32_to_extF80M( int32_t a, extFloat80_t *zPtr ) { struct extFloat80M *zSPtr; uint_fast16_t uiZ64; uint64_t sigZ; bool sign; uint32_t absA; int_fast8_t shiftDist; zSPtr = (struct extFloat80M *) zPtr; uiZ64 = 0; sigZ = 0; if ( a ) { sign = (a < 0); absA = sign ? -(uint32_t) a : (uint32_t) a; shiftDist = softfloat_countLeadingZeros32( absA ); uiZ64 = packToExtF80UI64( sign, 0x401E - shiftDist ); sigZ = (uint64_t) (absA<<shiftDist)<<32; } zSPtr->signExp = uiZ64; zSPtr->signif = sigZ; }
void softfloat_normRoundPackMToExtF80M( bool sign, int32_t exp, uint32_t *extSigPtr, uint_fast8_t roundingPrecision, struct extFloat80M *zSPtr ) { int_fast16_t shiftCount; uint32_t wordSig; shiftCount = 0; wordSig = extSigPtr[indexWord( 3, 2 )]; if ( ! wordSig ) { shiftCount = 32; wordSig = extSigPtr[indexWord( 3, 1 )]; if ( ! wordSig ) { shiftCount = 64; wordSig = extSigPtr[indexWord( 3, 0 )]; if ( ! wordSig ) { zSPtr->signExp = packToExtF80UI64( sign, 0 ); zSPtr->signif = 0; return; } } } shiftCount += softfloat_countLeadingZeros32( wordSig ); if ( shiftCount ) { exp -= shiftCount; softfloat_shiftLeft96M( extSigPtr, shiftCount, extSigPtr ); } softfloat_roundPackMToExtF80M( sign, exp, extSigPtr, roundingPrecision, zSPtr ); }
extFloat80_t extF80_mul( extFloat80_t a, extFloat80_t b ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64; uint_fast64_t uiA0; bool signA; int_fast32_t expA; uint_fast64_t sigA; union { struct extFloat80M s; extFloat80_t f; } uB; uint_fast16_t uiB64; uint_fast64_t uiB0; bool signB; int_fast32_t expB; uint_fast64_t sigB; bool signZ; uint_fast64_t magBits; struct exp32_sig64 normExpSig; int_fast32_t expZ; struct uint128 sig128Z, uiZ; uint_fast16_t uiZ64; uint_fast64_t uiZ0; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.s.signExp; uiA0 = uA.s.signif; signA = signExtF80UI64( uiA64 ); expA = expExtF80UI64( uiA64 ); sigA = uiA0; uB.f = b; uiB64 = uB.s.signExp; uiB0 = uB.s.signif; signB = signExtF80UI64( uiB64 ); expB = expExtF80UI64( uiB64 ); sigB = uiB0; signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FFF ) { if ( (sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) || ((expB == 0x7FFF) && (sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) ) { goto propagateNaN; } magBits = expB | sigB; goto infArg; } if ( expB == 0x7FFF ) { if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; magBits = expA | sigA; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) expA = 1; if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); expA += normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) expB = 1; if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalExtF80Sig( sigB ); expB += normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FFE; sig128Z = softfloat_mul64To128( sigA, sigB ); if ( sig128Z.v64 < UINT64_C( 0x8000000000000000 ) ) { --expZ; sig128Z = softfloat_add128( sig128Z.v64, sig128Z.v0, sig128Z.v64, sig128Z.v0 ); } return softfloat_roundPackToExtF80( signZ, expZ, sig128Z.v64, sig128Z.v0, extF80_roundingPrecision ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); uiZ64 = uiZ.v64; uiZ0 = uiZ.v0; goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ64 = defaultNaNExtF80UI64; uiZ0 = defaultNaNExtF80UI0; } else { uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); uiZ0 = UINT64_C( 0x8000000000000000 ); } goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ64 = packToExtF80UI64( signZ, 0 ); uiZ0 = 0; uiZ: uZ.s.signExp = uiZ64; uZ.s.signif = uiZ0; return uZ.f; }
void softfloat_roundPackMToExtF80M( bool sign, int32_t exp, uint32_t *extSigPtr, uint_fast8_t roundingPrecision, struct extFloat80M *zSPtr ) { uint_fast8_t roundingMode; bool roundNearEven; uint64_t sig, roundIncrement, roundMask, roundBits; bool isTiny; uint32_t sigExtra; bool doIncrement; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; if ( roundingPrecision == 80 ) goto precision80; if ( roundingPrecision == 64 ) { roundIncrement = UINT64_C( 0x0000000000000400 ); roundMask = UINT64_C( 0x00000000000007FF ); } else if ( roundingPrecision == 32 ) { roundIncrement = UINT64_C( 0x0000008000000000 ); roundMask = UINT64_C( 0x000000FFFFFFFFFF ); } else { goto precision80; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( extSigPtr[indexWordLo( 3 )] ) sig |= 1; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? roundMask : 0; } roundBits = sig & roundMask; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x7FFD <= (uint32_t) (exp - 1) ) { if ( exp <= 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < 0) || (sig <= (uint64_t) (sig + roundIncrement)); sig = softfloat_shiftRightJam64( sig, 1 - exp ); roundBits = sig & roundMask; if ( roundBits ) { if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= roundMask + 1; } #endif } sig += roundIncrement; exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) ) { goto overflow; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig = (sig & ~roundMask) | (roundMask + 1); goto packReturn; } #endif } sig += roundIncrement; if ( sig < roundIncrement ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; goto packReturn; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ precision80: sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x7FFD <= (uint32_t) (exp - 1) ) { if ( exp <= 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < 0) || ! doIncrement || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); softfloat_shiftRightJam96M( extSigPtr, 1 - exp, extSigPtr ); exp = 0; sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; sigExtra = extSigPtr[indexWordLo( 3 )]; if ( sigExtra ) { if ( isTiny ) softfloat_raiseFlags( softfloat_flag_underflow ); softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= 1; goto packReturn; } #endif } doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( doIncrement ) { ++sig; sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); } goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) && doIncrement) ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ roundMask = 0; overflow: softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) || (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ) { exp = 0x7FFF; sig = UINT64_C( 0x8000000000000000 ); } else { exp = 0x7FFE; sig = ~roundMask; } goto packReturn; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= 1; goto packReturn; } #endif } if ( doIncrement ) { ++sig; if ( ! sig ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } else { sig &= ~(uint64_t) (! (sigExtra & 0x7FFFFFFF) & roundNearEven); } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ packReturn: zSPtr->signExp = packToExtF80UI64( sign, exp ); zSPtr->signif = sig; }
extFloat80_t softfloat_subMagsExtF80( uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0, bool signZ ) { int_fast32_t expA; uint_fast64_t sigA; int_fast32_t expB; uint_fast64_t sigB; int_fast32_t expDiff; uint_fast16_t uiZ64; uint_fast64_t uiZ0; int_fast32_t expZ; uint_fast64_t sigExtra; struct uint128 sig128, uiZ; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expA = expExtF80UI64( uiA64 ); sigA = uiA0; expB = expExtF80UI64( uiB64 ); sigB = uiB0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; if ( 0 < expDiff ) goto expABigger; if ( expDiff < 0 ) goto expBBigger; if ( expA == 0x7FFF ) { if ( (sigA | sigB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { goto propagateNaN; } softfloat_raiseFlags( softfloat_flag_invalid ); uiZ64 = defaultNaNExtF80UI64; uiZ0 = defaultNaNExtF80UI0; goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA; if ( ! expZ ) expZ = 1; sigExtra = 0; if ( sigB < sigA ) goto aBigger; if ( sigA < sigB ) goto bBigger; uiZ64 = packToExtF80UI64( (softfloat_roundingMode == softfloat_round_min), 0 ); uiZ0 = 0; goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expBBigger: if ( expB == 0x7FFF ) { if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = packToExtF80UI64( signZ ^ 1, 0x7FFF ); uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; } if ( ! expA ) { ++expDiff; sigExtra = 0; if ( ! expDiff ) goto newlyAlignedBBigger; } sig128 = softfloat_shiftRightJam128( sigA, 0, -expDiff ); sigA = sig128.v64; sigExtra = sig128.v0; newlyAlignedBBigger: expZ = expB; bBigger: signZ ^= 1; sig128 = softfloat_sub128( sigB, 0, sigA, sigExtra ); goto normRoundPack; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expABigger: if ( expA == 0x7FFF ) { if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = uiA64; uiZ0 = uiA0; goto uiZ; } if ( ! expB ) { --expDiff; sigExtra = 0; if ( ! expDiff ) goto newlyAlignedABigger; } sig128 = softfloat_shiftRightJam128( sigB, 0, expDiff ); sigB = sig128.v64; sigExtra = sig128.v0; newlyAlignedABigger: expZ = expA; aBigger: sig128 = softfloat_sub128( sigA, 0, sigB, sigExtra ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ normRoundPack: return softfloat_normRoundPackToExtF80( signZ, expZ, sig128.v64, sig128.v0, extF80_roundingPrecision ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); uiZ64 = uiZ.v64; uiZ0 = uiZ.v0; uiZ: uZ.s.signExp = uiZ64; uZ.s.signif = uiZ0; return uZ.f; }
extFloat80_t extF80_roundToInt( extFloat80_t a, uint_fast8_t roundingMode, bool exact ) { union { struct extFloat80M s; extFloat80_t f; } uA; uint_fast16_t uiA64, signUI64; int_fast32_t exp; uint_fast64_t sigA; uint_fast16_t uiZ64; uint_fast64_t sigZ; struct exp32_sig64 normExpSig; struct uint128 uiZ; uint_fast64_t lastBitMask, roundBitsMask; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.s.signExp; signUI64 = uiA64 & packToExtF80UI64( 1, 0 ); exp = expExtF80UI64( uiA64 ); sigA = uA.s.signif; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! (sigA & UINT64_C( 0x8000000000000000 )) && (exp != 0x7FFF) ) { if ( ! sigA ) { uiZ64 = signUI64; sigZ = 0; goto uiZ; } normExpSig = softfloat_normSubnormalExtF80Sig( sigA ); exp += normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x403E <= exp ) { if ( exp == 0x7FFF ) { if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { uiZ = softfloat_propagateNaNExtF80UI( uiA64, sigA, 0, 0 ); uiZ64 = uiZ.v64; sigZ = uiZ.v0; goto uiZ; } sigZ = UINT64_C( 0x8000000000000000 ); } else { sigZ = sigA; } uiZ64 = signUI64 | exp; goto uiZ; } if ( exp <= 0x3FFE ) { if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; switch ( roundingMode ) { case softfloat_round_near_even: if ( ! (sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) break; case softfloat_round_near_maxMag: if ( exp == 0x3FFE ) goto mag1; break; case softfloat_round_min: if ( signUI64 ) goto mag1; break; case softfloat_round_max: if ( ! signUI64 ) goto mag1; break; } uiZ64 = signUI64; sigZ = 0; goto uiZ; mag1: uiZ64 = signUI64 | 0x3FFF; sigZ = UINT64_C( 0x8000000000000000 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ64 = signUI64 | exp; lastBitMask = (uint_fast64_t) 1<<(0x403E - exp); roundBitsMask = lastBitMask - 1; sigZ = sigA; if ( roundingMode == softfloat_round_near_maxMag ) { sigZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_near_even ) {
extFloat80_t softfloat_addMagsExtF80( uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0, bool signZ ) { int_fast32_t expA; uint_fast64_t sigA; int_fast32_t expB; uint_fast64_t sigB; int_fast32_t expDiff; uint_fast16_t uiZ64; uint_fast64_t uiZ0, sigZ, sigZExtra; struct exp32_sig64 normExpSig; int_fast32_t expZ; struct uint64_extra sig64Extra; struct uint128 uiZ; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expA = expExtF80UI64( uiA64 ); sigA = uiA0; expB = expExtF80UI64( uiB64 ); sigB = uiB0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; if ( ! expDiff ) { if ( expA == 0x7FFF ) { if ( (sigA | sigB) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { goto propagateNaN; } uiZ64 = uiA64; uiZ0 = uiA0; goto uiZ; } sigZ = sigA + sigB; sigZExtra = 0; if ( ! expA ) { normExpSig = softfloat_normSubnormalExtF80Sig( sigZ ); expZ = normExpSig.exp + 1; sigZ = normExpSig.sig; goto roundAndPack; } expZ = expA; goto shiftRight1; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expDiff < 0 ) { if ( expB == 0x7FFF ) { if ( sigB & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); uiZ0 = uiB0; goto uiZ; } expZ = expB; if ( ! expA ) { ++expDiff; sigZExtra = 0; if ( ! expDiff ) goto newlyAligned; } sig64Extra = softfloat_shiftRightJam64Extra( sigA, 0, -expDiff ); sigA = sig64Extra.v; sigZExtra = sig64Extra.extra; } else { if ( expA == 0x7FFF ) { if ( sigA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) goto propagateNaN; uiZ64 = uiA64; uiZ0 = uiA0; goto uiZ; } expZ = expA; if ( ! expB ) { --expDiff; sigZExtra = 0; if ( ! expDiff ) goto newlyAligned; } sig64Extra = softfloat_shiftRightJam64Extra( sigB, 0, expDiff ); sigB = sig64Extra.v; sigZExtra = sig64Extra.extra; } newlyAligned: sigZ = sigA + sigB; if ( sigZ & UINT64_C( 0x8000000000000000 ) ) goto roundAndPack; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftRight1: sig64Extra = softfloat_shortShiftRightJam64Extra( sigZ, sigZExtra, 1 ); sigZ = sig64Extra.v | UINT64_C( 0x8000000000000000 ); sigZExtra = sig64Extra.extra; ++expZ; roundAndPack: return softfloat_roundPackToExtF80( signZ, expZ, sigZ, sigZExtra, extF80_roundingPrecision ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNExtF80UI( uiA64, uiA0, uiB64, uiB0 ); uiZ64 = uiZ.v64; uiZ0 = uiZ.v0; uiZ: uZ.s.signExp = uiZ64; uZ.s.signif = uiZ0; return uZ.f; }
extFloat80_t softfloat_roundPackToExtF80( bool sign, int_fast32_t exp, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingPrecision ) { uint_fast8_t roundingMode; bool roundNearEven; uint_fast64_t roundIncrement, roundMask, roundBits; bool isTiny, doIncrement; struct uint64_extra sig64Extra; union { struct extFloat80M s; extFloat80_t f; } uZ; roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); if ( roundingPrecision == 80 ) goto precision80; if ( roundingPrecision == 64 ) { roundIncrement = UINT64_C( 0x0000000000000400 ); roundMask = UINT64_C( 0x00000000000007FF ); } else if ( roundingPrecision == 32 ) { roundIncrement = UINT64_C( 0x0000008000000000 ); roundMask = UINT64_C( 0x000000FFFFFFFFFF ); } else { goto precision80; } sig |= (sigExtra != 0); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? roundMask : 0; } roundBits = sig & roundMask; if ( 0x7FFD <= (uint32_t) (exp - 1) ) { if ( exp <= 0 ) { isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < 0) || (sig <= (uint64_t) (sig + roundIncrement)); sig = softfloat_shiftRightJam64( sig, 1 - exp ); roundBits = sig & roundMask; if ( isTiny && roundBits ) { softfloat_raiseFlags( softfloat_flag_underflow ); } if ( roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } sig += roundIncrement; exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig)) ) { goto overflow; } } if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact; sig = (uint64_t) (sig + roundIncrement); if ( sig < roundIncrement ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } roundIncrement = roundMask + 1; if ( roundNearEven && (roundBits<<1 == roundIncrement) ) { roundMask |= roundIncrement; } sig &= ~roundMask; if ( ! sig ) exp = 0; goto packReturn; precision80: doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( 0x7FFD <= (uint32_t) (exp - 1) ) { if ( exp <= 0 ) { isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < 0) || ! doIncrement || (sig < UINT64_C( 0xFFFFFFFFFFFFFFFF )); sig64Extra = softfloat_shiftRightJam64Extra( sig, sigExtra, 1 - exp ); sig = sig64Extra.v; sigExtra = sig64Extra.extra; if ( isTiny && sigExtra ) { softfloat_raiseFlags( softfloat_flag_underflow ); } if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } exp = 0; if ( doIncrement ) { ++sig; sig &= ~(uint_fast64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); exp = ((sig & UINT64_C( 0x8000000000000000 )) != 0); } goto packReturn; } if ( (0x7FFE < exp) || ((exp == 0x7FFE) && (sig == UINT64_C( 0xFFFFFFFFFFFFFFFF )) && doIncrement) ) { roundMask = 0; overflow: softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) || (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ) { exp = 0x7FFF; sig = UINT64_C( 0x8000000000000000 ); } else { exp = 0x7FFE; sig = ~roundMask; } goto packReturn; } } if ( sigExtra ) softfloat_exceptionFlags |= softfloat_flag_inexact; if ( doIncrement ) { ++sig; if ( ! sig ) { ++exp; sig = UINT64_C( 0x8000000000000000 ); } else { sig &= ~(uint_fast64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); } } else { if ( ! sig ) exp = 0; } packReturn: uZ.s.signExp = packToExtF80UI64( sign, exp ); uZ.s.signif = sig; return uZ.f; }
void extF80M_mul( const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) { const struct extFloat80M *aSPtr, *bSPtr; struct extFloat80M *zSPtr; uint_fast16_t uiA64; int32_t expA; uint_fast16_t uiB64; int32_t expB; bool signZ; uint_fast16_t exp, uiZ64; uint64_t uiZ0, sigA, sigB; int32_t expZ; uint32_t sigProd[4], *extSigZPtr; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ aSPtr = (const struct extFloat80M *) aPtr; bSPtr = (const struct extFloat80M *) bPtr; zSPtr = (struct extFloat80M *) zPtr; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiA64 = aSPtr->signExp; expA = expExtF80UI64( uiA64 ); uiB64 = bSPtr->signExp; expB = expExtF80UI64( uiB64 ); signZ = signExtF80UI64( uiA64 ) ^ signExtF80UI64( uiB64 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (expA == 0x7FFF) || (expB == 0x7FFF) ) { if ( softfloat_tryPropagateNaNExtF80M( aSPtr, bSPtr, zSPtr ) ) return; if ( (! aSPtr->signif && (expA != 0x7FFF)) || (! bSPtr->signif && (expB != 0x7FFF)) ) { softfloat_invalidExtF80M( zSPtr ); return; } uiZ64 = packToExtF80UI64( signZ, 0x7FFF ); uiZ0 = UINT64_C( 0x8000000000000000 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) expA = 1; sigA = aSPtr->signif; if ( ! (sigA & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigA ) goto zero; expA += softfloat_normExtF80SigM( &sigA ); } if ( ! expB ) expB = 1; sigB = bSPtr->signif; if ( ! (sigB & UINT64_C( 0x8000000000000000 )) ) { if ( ! sigB ) goto zero; expB += softfloat_normExtF80SigM( &sigB ); } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FFE; softfloat_mul64To128M( sigA, sigB, sigProd ); if ( sigProd[indexWordLo( 4 )] ) sigProd[indexWord( 4, 1 )] |= 1; extSigZPtr = &sigProd[indexMultiwordHi( 4, 3 )]; if ( sigProd[indexWordHi( 4 )] < 0x80000000 ) { --expZ; softfloat_add96M( extSigZPtr, extSigZPtr, extSigZPtr ); } softfloat_roundPackMToExtF80M( signZ, expZ, extSigZPtr, extF80_roundingPrecision, zSPtr ); return; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ64 = packToExtF80UI64( signZ, 0 ); uiZ0 = 0; uiZ: zSPtr->signExp = uiZ64; zSPtr->signif = uiZ0; }