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 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_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 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; }
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; }