float128_t ui64_to_f128( uint64_t a ) { uint_fast64_t uiZ64, uiZ0; int_fast8_t shiftCount; struct uint128 zSig; union ui128_f128 uZ; if ( ! a ) { uiZ64 = 0; uiZ0 = 0; } else { shiftCount = softfloat_countLeadingZeros64( a ) + 49; if ( 64 <= shiftCount ) { zSig.v64 = a<<(shiftCount - 64); zSig.v0 = 0; } else { zSig = softfloat_shortShiftLeft128( 0, a, shiftCount ); } uiZ64 = packToF128UI64( 0, 0x406E - shiftCount, zSig.v64 ); uiZ0 = zSig.v0; } uZ.ui.v64 = uiZ64; uZ.ui.v0 = uiZ0; return uZ.f; }
float16_t i64_to_f16( int64_t a ) { bool sign; uint_fast64_t absA; int_fast8_t shiftDist; union ui16_f16 u; uint_fast16_t sig; sign = (a < 0); absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; shiftDist = softfloat_countLeadingZeros64( absA ) - 53; if ( 0 <= shiftDist ) { u.ui = a ? packToF16UI( sign, 0x18 - shiftDist, (uint_fast16_t) absA<<shiftDist ) : 0; return u.f; } else { shiftDist += 4; sig = (shiftDist < 0) ? softfloat_shortShiftRightJam64( absA, -shiftDist ) : (uint_fast16_t) absA<<shiftDist; return softfloat_roundPackToF16( sign, 0x1C - shiftDist, sig ); } }
float32_t i64_to_f32( int_fast64_t a ) { bool sign; uint_fast64_t absA; int shiftCount; union ui32_f32 u; uint_fast32_t sig; sign = ( a < 0 ); absA = sign ? - (uint_fast64_t) a : a; shiftCount = softfloat_countLeadingZeros64( absA ) - 40; if ( 0 <= shiftCount ) { u.ui = a ? packToF32UI( sign, 0x95 - shiftCount, (uint_fast32_t) absA<<shiftCount ) : 0; return u.f; } else { shiftCount += 7; sig = ( shiftCount < 0 ) ? softfloat_shortShift64RightJam( absA, - shiftCount ) : (uint_fast32_t) absA<<shiftCount; return softfloat_roundPackToF32( sign, 0x9C - shiftCount, sig ); } }
extFloat80_t softfloat_normRoundPackToExtF80( bool sign, int_fast32_t exp, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingPrecision ) { int_fast8_t shiftDist; struct uint128 sig128; if ( ! sig ) { exp -= 64; sig = sigExtra; sigExtra = 0; } shiftDist = softfloat_countLeadingZeros64( sig ); exp -= shiftDist; if ( shiftDist ) { sig128 = softfloat_shortShiftLeft128( sig, sigExtra, shiftDist ); sig = sig128.v64; sigExtra = sig128.v0; } return softfloat_roundPackToExtF80( sign, exp, sig, sigExtra, roundingPrecision ); }
float128_t i64_to_f128( int64_t a ) { uint_fast64_t uiZ64, uiZ0; bool sign; uint_fast64_t absA; int_fast8_t shiftCount; struct uint128 zSig; union ui128_f128 uZ; if ( ! a ) { uiZ64 = 0; uiZ0 = 0; } else { sign = (a < 0); absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; shiftCount = softfloat_countLeadingZeros64( absA ) + 49; if ( 64 <= shiftCount ) { zSig.v64 = absA<<(shiftCount - 64); zSig.v0 = 0; } else { zSig = softfloat_shortShiftLeft128( 0, absA, shiftCount ); } uiZ64 = packToF128UI64( sign, 0x406E - shiftCount, zSig.v64 ); uiZ0 = zSig.v0; } uZ.ui.v64 = uiZ64; uZ.ui.v0 = uiZ0; return uZ.f; }
void ui64_to_f128M( uint64_t a, float128_t *zPtr ) { uint32_t *zWPtr, uiZ96, uiZ64; uint_fast8_t shiftCount; uint32_t *ptr; zWPtr = (uint32_t *) zPtr; uiZ96 = 0; uiZ64 = 0; zWPtr[indexWord( 4, 1 )] = 0; zWPtr[indexWord( 4, 0 )] = 0; if ( a ) { shiftCount = softfloat_countLeadingZeros64( a ) + 17; if ( shiftCount < 32 ) { ptr = zWPtr + indexMultiwordHi( 4, 3 ); ptr[indexWord( 3, 2 )] = 0; ptr[indexWord( 3, 1 )] = a>>32; ptr[indexWord( 3, 0 )] = a; softfloat_shortShiftLeft96M( ptr, shiftCount, ptr ); ptr[indexWordHi( 3 )] = packToF128UI96( 0, 0x404E - shiftCount, ptr[indexWordHi( 3 )] ); return; } a <<= shiftCount - 32; uiZ96 = packToF128UI96( 0, 0x404E - shiftCount, a>>32 ); uiZ64 = a; }
int softfloat_normExtF80SigM( uint64_t *sigPtr ) { uint64_t sig; int_fast8_t shiftDist; sig = *sigPtr; shiftDist = softfloat_countLeadingZeros64( sig ); *sigPtr = sig<<shiftDist; return -shiftDist; }
struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t sig ) { int_fast8_t shiftCount; struct exp32_sig64 z; shiftCount = softfloat_countLeadingZeros64( sig ); z.exp = -shiftCount; z.sig = sig<<shiftCount; return z; }
struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t sig ) { int_fast8_t shiftDist; struct exp16_sig64 z; shiftDist = softfloat_countLeadingZeros64( sig ) - 11; z.exp = 1 - shiftDist; z.sig = sig<<shiftDist; return z; }
struct exp32_sig128 softfloat_normSubnormalF128Sig( uint_fast64_t sig64, uint_fast64_t sig0 ) { int_fast8_t shiftDist; struct exp32_sig128 z; if ( ! sig64 ) { shiftDist = softfloat_countLeadingZeros64( sig0 ) - 15; z.exp = -63 - shiftDist; if ( shiftDist < 0 ) { z.sig.v64 = sig0>>-shiftDist; z.sig.v0 = sig0<<(shiftDist & 63); } else {
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 ); } }
extFloat80_t ui64_to_extF80( uint64_t a ) { uint_fast16_t uiZ64; int_fast8_t shiftCount; union { struct extFloat80M s; extFloat80_t f; } uZ; uiZ64 = 0; if ( a ) { shiftCount = softfloat_countLeadingZeros64( a ); uiZ64 = 0x403E - shiftCount; a <<= shiftCount; } uZ.s.signExp = uiZ64; uZ.s.signif = a; return uZ.f; }
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; }
float128_t softfloat_normRoundPackToF128( bool sign, int_fast32_t exp, uint_fast64_t sig64, uint_fast64_t sig0 ) { int_fast8_t shiftDist; struct uint128 sig128; union ui128_f128 uZ; uint_fast64_t sigExtra; struct uint128_extra sig128Extra; if ( ! sig64 ) { exp -= 64; sig64 = sig0; sig0 = 0; } shiftDist = softfloat_countLeadingZeros64( sig64 ) - 15; exp -= shiftDist; if ( 0 <= shiftDist ) { if ( shiftDist ) { sig128 = softfloat_shortShiftLeft128( sig64, sig0, shiftDist ); sig64 = sig128.v64; sig0 = sig128.v0; } if ( (uint32_t) exp < 0x7FFD ) { uZ.ui.v64 = packToF128UI64( sign, sig64 | sig0 ? exp : 0, sig64 ); uZ.ui.v0 = sig0; return uZ.f; } sigExtra = 0; } else { sig128Extra = softfloat_shortShiftRightJam128Extra( sig64, sig0, 0, -shiftDist ); sig64 = sig128Extra.v.v64; sig0 = sig128Extra.v.v0; sigExtra = sig128Extra.extra; } return softfloat_roundPackToF128( sign, exp, sig64, sig0, sigExtra ); }
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; }
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; }