uint_fast16_t f128_classify( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uint_fast16_t infOrNaN = expF128UI64( uiA64 ) == 0x7FFF; uint_fast16_t subnormalOrZero = expF128UI64( uiA64 ) == 0; bool sign = signF128UI64( uiA64 ); bool fracZero = fracF128UI64( uiA64 ) == 0 && uiA0 == 0; bool isNaN = isNaNF128UI( uiA64, uiA0 ); bool isSNaN = softfloat_isSigNaNF128UI( uiA64, uiA0 ); return ( sign && infOrNaN && fracZero ) << 0 | ( sign && !infOrNaN && !subnormalOrZero ) << 1 | ( sign && subnormalOrZero && !fracZero ) << 2 | ( sign && subnormalOrZero && fracZero ) << 3 | ( !sign && infOrNaN && fracZero ) << 7 | ( !sign && !infOrNaN && !subnormalOrZero ) << 6 | ( !sign && subnormalOrZero && !fracZero ) << 5 | ( !sign && subnormalOrZero && fracZero ) << 4 | ( isNaN && isSNaN ) << 8 | ( isNaN && !isSNaN ) << 9; }
uint_fast32_t f128_to_ui32( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftCount; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); sig64 |= (sig0 != 0); shiftCount = 0x4028 - exp; if ( 0 < shiftCount ) { sig64 = softfloat_shiftRightJam64( sig64, shiftCount ); } return softfloat_roundPackToUI32( sign, sig64, roundingMode, exact ); }
int_fast32_t f128_to_i32_r_minMag( float128_t a, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; int_fast32_t exp; uint_fast64_t sig64; int_fast32_t shiftDist; bool sign; int_fast32_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( 49 <= shiftDist ) { if ( exact && (exp | sig64) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF128UI64( uiA64 ); if ( shiftDist < 18 ) { if ( sign && (shiftDist == 17) && (sig64 < UINT64_C( 0x0000000000020000 )) ) { if ( exact && sig64 ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return -0x7FFFFFFF - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && sig64 ? i32_fromNaN : sign ? i32_fromNegOverflow : i32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig64 |= UINT64_C( 0x0001000000000000 ); absZ = sig64>>shiftDist; if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ<<shiftDist != sig64) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sign ? -absZ : absZ; }
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; }
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; }
uint_fast64_t f128_to_ui64( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftDist; struct uint128 sig128; struct uint64_extra sigExtra; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( shiftDist <= 0 ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( shiftDist < -15 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && (sig64 | sig0) ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sig64 |= UINT64_C( 0x0001000000000000 ); if ( shiftDist ) { sig128 = softfloat_shortShiftLeft128( sig64, sig0, -shiftDist ); sig64 = sig128.v64; sig0 = sig128.v0; } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); sigExtra = softfloat_shiftRightJam64Extra( sig64, sig0, shiftDist ); sig64 = sigExtra.v; sig0 = sigExtra.extra; } return softfloat_roundToUI64( sign, sig64, sig0, roundingMode, exact ); }
float32_t f128_to_f32( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t frac64; struct commonNaN commonNaN; uint_fast32_t uiZ, frac32; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); frac64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( frac64 ) { softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac32 = softfloat_shortShiftRightJam64( frac64, 18 ); if ( ! (exp | frac32) ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ exp -= 0x3F81; if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF32( sign, exp, frac32 | 0x40000000 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; }
uint_fast32_t f128_to_ui32_r_minMag( float128_t a, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; int_fast32_t exp; uint_fast64_t sig64; int_fast32_t shiftDist; bool sign; uint_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( 49 <= shiftDist ) { if ( exact && (exp | sig64) ) { softfloat_raiseFlags( softfloat_flag_inexact ); } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF128UI64( uiA64 ); if ( sign || (shiftDist < 17) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && sig64 ? ui32_fromNaN : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig64 |= UINT64_C( 0x0001000000000000 ); z = sig64>>shiftDist; if ( exact && ((uint_fast64_t) z<<shiftDist != sig64) ) { softfloat_raiseFlags( softfloat_flag_inexact ); } return z; }
int_fast64_t f128_to_i64( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftCount; struct uint128 sig128; struct uint64_extra sigExtra; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; shiftCount = 0x402F - exp; if ( shiftCount <= 0 ) { if ( shiftCount < -15 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return ! sign || ((exp == 0x7FFF) && (sig64 | sig0)) ? INT64_C( 0x7FFFFFFFFFFFFFFF ) : -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } sig64 |= UINT64_C( 0x0001000000000000 ); if ( shiftCount ) { sig128 = softfloat_shortShiftLeft128( sig64, sig0, -shiftCount ); sig64 = sig128.v64; sig0 = sig128.v0; } } else { if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); sigExtra = softfloat_shiftRightJam64Extra( sig64, sig0, shiftCount ); sig64 = sigExtra.v; sig0 = sigExtra.extra; } return softfloat_roundPackToI64( sign, sig64, sig0, roundingMode, exact ); }
uint_fast32_t f128_to_ui32( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64; int_fast32_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) if ( (exp == 0x7FFF) && sig64 ) { #if (ui32_fromNaN == ui32_fromPosOverflow) sign = 0; #elif (ui32_fromNaN == ui32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return ui32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); shiftDist = 0x4023 - exp; if ( 0 < shiftDist ) { sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); } return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); }
float128_t f128_roundToInt( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; int_fast32_t exp; struct uint128 uiZ; uint_fast64_t lastBitMask, roundBitsMask; bool roundNearEven; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; exp = expF128UI64( uiA64 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x402F <= exp ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( 0x406F <= exp ) { if ( (exp == 0x7FFF) && (fracF128UI64( uiA64 ) | uiA0) ) { uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, 0, 0 ); goto uiZ; } return a; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ lastBitMask = (uint_fast64_t) 2<<(0x406E - exp); roundBitsMask = lastBitMask - 1; uiZ.v64 = uiA64; uiZ.v0 = uiA0; roundNearEven = (roundingMode == softfloat_round_near_even); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) ) { if ( exp == 0x402F ) { if ( UINT64_C( 0x8000000000000000 ) <= uiZ.v0 ) { ++uiZ.v64; if ( roundNearEven && (uiZ.v0 == UINT64_C( 0x8000000000000000 )) ) { uiZ.v64 &= ~1; } } } else { uiZ = softfloat_add128( uiZ.v64, uiZ.v0, 0, lastBitMask>>1 ); if ( roundNearEven && ! (uiZ.v0 & roundBitsMask) ) { uiZ.v0 &= ~lastBitMask; } } } else if ( roundingMode != softfloat_round_minMag ) { if ( signF128UI64( uiZ.v64 ) ^ (roundingMode == softfloat_round_max) ) { uiZ = softfloat_add128( uiZ.v64, uiZ.v0, 0, roundBitsMask ); } } uiZ.v0 &= ~roundBitsMask; } else {
float128_t f128_mul( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool signA; int_fast32_t expA; struct uint128 sigA; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signB; int_fast32_t expB; struct uint128 sigB; bool signZ; uint_fast64_t magBits; struct exp32_sig128 normExpSig; int_fast32_t expZ; uint64_t sig256Z[4]; uint_fast64_t sigZExtra; struct uint128 sigZ; struct uint128_extra sig128Extra; struct uint128 uiZ; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; signA = signF128UI64( uiA64 ); expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; signB = signF128UI64( uiB64 ); expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FFF ) { if ( (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) ) { goto propagateNaN; } magBits = expB | sigB.v64 | sigB.v0; goto infArg; } if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; magBits = expA | sigA.v64 | sigA.v0; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! (sigA.v64 | sigA.v0) ) goto zero; normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! (sigB.v64 | sigB.v0) ) goto zero; normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x4000; sigA.v64 |= UINT64_C( 0x0001000000000000 ); sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 16 ); softfloat_mul128To256M( sigA.v64, sigA.v0, sigB.v64, sigB.v0, sig256Z ); sigZExtra = sig256Z[indexWord( 4, 1 )] | (sig256Z[indexWord( 4, 0 )] != 0); sigZ = softfloat_add128( sig256Z[indexWord( 4, 3 )], sig256Z[indexWord( 4, 2 )], sigA.v64, sigA.v0 ); if ( UINT64_C( 0x0002000000000000 ) <= sigZ.v64 ) { ++expZ; sig128Extra = softfloat_shortShiftRightJam128Extra( sigZ.v64, sigZ.v0, sigZExtra, 1 ); sigZ = sig128Extra.v; sigZExtra = sig128Extra.extra; } return softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; goto uiZ; } uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); goto uiZ0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ.v64 = packToF128UI64( signZ, 0, 0 ); uiZ0: uiZ.v0 = 0; uiZ: uZ.ui = uiZ; return uZ.f; }
float128_t softfloat_addMagsF128( uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0, bool signZ ) { int_fast32_t expA; struct uint128 sigA; int_fast32_t expB; struct uint128 sigB; int_fast32_t expDiff; struct uint128 uiZ, sigZ; int_fast32_t expZ; uint_fast64_t sigZExtra; struct uint128_extra sig128Extra; union ui128_f128 uZ; expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; expDiff = expA - expB; if ( ! expDiff ) { if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 | sigB.v64 | sigB.v0 ) goto propagateNaN; uiZ.v64 = uiA64; uiZ.v0 = uiA0; goto uiZ; } sigZ = softfloat_add128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ); if ( ! expA ) { uiZ.v64 = packToF128UI64( signZ, 0, sigZ.v64 ); uiZ.v0 = sigZ.v0; goto uiZ; } expZ = expA; sigZ.v64 |= UINT64_C( 0x0002000000000000 ); sigZExtra = 0; goto shiftRight1; } if ( expDiff < 0 ) { if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); uiZ.v0 = 0; goto uiZ; } expZ = expB; if ( expA ) { sigA.v64 |= UINT64_C( 0x0001000000000000 ); } else { ++expDiff; sigZExtra = 0; if ( ! expDiff ) goto newlyAligned; } sig128Extra = softfloat_shiftRightJam128Extra( sigA.v64, sigA.v0, 0, -expDiff ); sigA = sig128Extra.v; sigZExtra = sig128Extra.extra; } else { if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 ) goto propagateNaN; uiZ.v64 = uiA64; uiZ.v0 = uiA0; goto uiZ; } expZ = expA; if ( expB ) { sigB.v64 |= UINT64_C( 0x0001000000000000 ); } else { --expDiff; sigZExtra = 0; if ( ! expDiff ) goto newlyAligned; } sig128Extra = softfloat_shiftRightJam128Extra( sigB.v64, sigB.v0, 0, expDiff ); sigB = sig128Extra.v; sigZExtra = sig128Extra.extra; } newlyAligned: sigZ = softfloat_add128( sigA.v64 | UINT64_C( 0x0001000000000000 ), sigA.v0, sigB.v64, sigB.v0 ); --expZ; if ( sigZ.v64 < UINT64_C( 0x0002000000000000 ) ) goto roundAndPack; ++expZ; shiftRight1: sig128Extra = softfloat_shortShiftRightJam128Extra( sigZ.v64, sigZ.v0, sigZExtra, 1 ); sigZ = sig128Extra.v; sigZExtra = sig128Extra.extra; roundAndPack: return softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); propagateNaN: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); uiZ: uZ.ui = uiZ; return uZ.f; }
float128_t softfloat_subMagsF128( uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0, bool signZ ) { int_fast32_t expA; struct uint128 sigA; int_fast32_t expB; struct uint128 sigB, sigZ; int_fast32_t expDiff, expZ; struct uint128 uiZ; union ui128_f128 uZ; expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; sigA = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 4 ); sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 4 ); expDiff = expA - expB; if ( 0 < expDiff ) goto expABigger; if ( expDiff < 0 ) goto expBBigger; if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 | sigB.v64 | sigB.v0 ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; goto uiZ; } expZ = expA; if ( ! expZ ) expZ = 1; if ( sigB.v64 < sigA.v64 ) goto aBigger; if ( sigA.v64 < sigB.v64 ) goto bBigger; if ( sigB.v0 < sigA.v0 ) goto aBigger; if ( sigA.v0 < sigB.v0 ) goto bBigger; uiZ.v64 = packToF128UI64( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); uiZ.v0 = 0; goto uiZ; expBBigger: if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; uiZ.v64 = packToF128UI64( signZ ^ 1, 0x7FFF, 0 ); uiZ.v0 = 0; goto uiZ; } if ( expA ) { sigA.v64 |= UINT64_C( 0x0010000000000000 ); } else { ++expDiff; if ( ! expDiff ) goto newlyAlignedBBigger; } sigA = softfloat_shiftRightJam128( sigA.v64, sigA.v0, -expDiff ); newlyAlignedBBigger: expZ = expB; sigB.v64 |= UINT64_C( 0x0010000000000000 ); bBigger: signZ = ! signZ; sigZ = softfloat_sub128( sigB.v64, sigB.v0, sigA.v64, sigA.v0 ); goto normRoundPack; expABigger: if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 ) goto propagateNaN; uiZ.v64 = uiA64; uiZ.v0 = uiA0; goto uiZ; } if ( expB ) { sigB.v64 |= UINT64_C( 0x0010000000000000 ); } else { --expDiff; if ( ! expDiff ) goto newlyAlignedABigger; } sigB = softfloat_shiftRightJam128( sigB.v64, sigB.v0, expDiff ); newlyAlignedABigger: expZ = expA; sigA.v64 |= UINT64_C( 0x0010000000000000 ); aBigger: sigZ = softfloat_sub128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ); normRoundPack: return softfloat_normRoundPackToF128( signZ, expZ - 5, sigZ.v64, sigZ.v0 ); propagateNaN: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); uiZ: uZ.ui = uiZ; return uZ.f; }