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 ) {
float32_t f64_to_f32( float64_t a ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; uint_fast32_t uiZ, sig32; union ui32_f32 uZ; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp == 0x7FF ) { uiZ = sig ? softfloat_commonNaNToF32UI( softfloat_f64UIToCommonNaN( uiA ) ) : packToF32UI( sign, 0xFF, 0 ); goto uiZ; } sig32 = softfloat_shortShift64RightJam( sig, 22 ); if ( ! ( exp | sig32 ) ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } return softfloat_roundPackToF32( sign, exp - 0x381, sig32 | 0x40000000 ); uiZ: uZ.ui = uiZ; return uZ.f; }
uint_fast64_t f64_to_ui64( float64_t a, int_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; struct uint64_extra sigExtra; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftCount = 0x433 - exp; if ( shiftCount <= 0 ) { if ( 0x43E < exp ) { softfloat_raiseFlags( softfloat_flag_invalid ); return UINT64_C( 0xFFFFFFFFFFFFFFFF ); } sigExtra.v = sig<<( - shiftCount ); sigExtra.extra = 0; } else { sigExtra = softfloat_shift64ExtraRightJam( sig, 0, shiftCount ); } return softfloat_roundPackToUI64( sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); }
void f64_to_f128M( float64_t a, float128_t *zPtr ) { uint32_t *zWPtr; union ui64_f64 uA; uint64_t uiA; bool sign; int_fast16_t exp; uint64_t sig; struct commonNaN commonNaN; uint32_t uiZ96; struct exp16_sig64 normExpSig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zWPtr = (uint32_t *) zPtr; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zWPtr[indexWord( 4, 0 )] = 0; if ( exp == 0x7FF ) { if ( sig ) { softfloat_f64UIToCommonNaN( uiA, &commonNaN ); softfloat_commonNaNToF128M( &commonNaN, zWPtr ); return; } uiZ96 = packToF128UI96( sign, 0x7FFF, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! sig ) { uiZ96 = packToF128UI96( sign, 0, 0 ); goto uiZ; } normExpSig = softfloat_normSubnormalF64Sig( sig ); exp = normExpSig.exp - 1; sig = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zWPtr[indexWord( 4, 1 )] = (uint32_t) sig<<28; sig >>= 4; zWPtr[indexWordHi( 4 )] = packToF128UI96( sign, exp + 0x3C00, sig>>32 ); zWPtr[indexWord( 4, 2 )] = sig; return; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: zWPtr[indexWord( 4, 3 )] = uiZ96; zWPtr[indexWord( 4, 2 )] = 0; zWPtr[indexWord( 4, 1 )] = 0; }
uint_fast32_t f64_to_ui32_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; uint_fast32_t z; uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp < 0x3FF ) { if ( exact && ( exp | sig ) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } if ( signF64UI( uiA ) || ( 0x41E < exp ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return 0xFFFFFFFF; } sig |= UINT64_C( 0x0010000000000000 ); shiftCount = 0x433 - exp; z = sig>>shiftCount; if ( exact && ( (uint_fast64_t) z<<shiftCount != sig ) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; }
extFloat80_t f64_to_extF80( float64_t a ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t frac; struct commonNaN commonNaN; struct uint128 uiZ; uint_fast16_t uiZ64; uint_fast64_t uiZ0; struct exp16_sig64 normExpSig; union { struct extFloat80M s; extFloat80_t f; } uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); frac = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FF ) { if ( frac ) { softfloat_f64UIToCommonNaN( 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_normSubnormalF64Sig( frac ); exp = normExpSig.exp; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ64 = packToExtF80UI64( sign, exp + 0x3C00 ); uiZ0 = (frac | UINT64_C( 0x0010000000000000 ))<<11; uiZ: uZ.s.signExp = uiZ64; uZ.s.signif = uiZ0; return uZ.f; }
int_fast64_t f64_to_i64( float64_t a, uint_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; #ifdef SOFTFLOAT_FAST_INT64 struct uint64_extra sigExtra; #else uint32_t extSig[3]; #endif uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftCount = 0x433 - exp; #ifdef SOFTFLOAT_FAST_INT64 if ( shiftCount <= 0 ) { if ( shiftCount < -11 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return ! sign || ((exp == 0x7FF) && (sig != UINT64_C( 0x0010000000000000 ))) ? INT64_C( 0x7FFFFFFFFFFFFFFF ) : -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } sigExtra.v = sig<<-shiftCount; sigExtra.extra = 0; } else { sigExtra = softfloat_shiftRightJam64Extra( sig, 0, shiftCount ); } return softfloat_roundPackToI64( sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); #else extSig[indexWord( 3, 0 )] = 0; if ( shiftCount <= 0 ) { if ( shiftCount < -11 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return ! sign || ((exp == 0x7FF) && (sig != UINT64_C( 0x0010000000000000 ))) ? INT64_C( 0x7FFFFFFFFFFFFFFF ) : -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } sig <<= -shiftCount; extSig[indexWord( 3, 2 )] = sig>>32; extSig[indexWord( 3, 1 )] = sig; } else {
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; }
int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftDist; bool sign; int_fast32_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x433 - exp; if ( 53 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF64UI( uiA ); if ( shiftDist < 22 ) { if ( sign && (exp == 0x41E) && (sig < UINT64_C( 0x0000000000200000 )) ) { if ( exact && sig ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return -0x7FFFFFFF - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && sig ? i32_fromNaN : sign ? i32_fromNegOverflow : i32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig |= UINT64_C( 0x0010000000000000 ); absZ = sig>>shiftDist; if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ<<shiftDist != sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sign ? -absZ : absZ; }
uint_fast64_t f64_to_ui64_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftDist; bool sign; uint_fast64_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x433 - exp; if ( 53 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF64UI( uiA ); if ( sign ) goto invalid; if ( shiftDist <= 0 ) { if ( shiftDist < -11 ) goto invalid; z = (sig | UINT64_C( 0x0010000000000000 ))<<-shiftDist; } else { sig |= UINT64_C( 0x0010000000000000 ); z = sig>>shiftDist; if ( exact && (uint64_t) (sig<<(-shiftDist & 63)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && sig ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; }
float128_t f64_to_f128( float64_t a ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; struct commonNaN commonNaN; struct uint128 uiZ; struct exp16_sig64 normExpSig; struct uint128 sig128; union ui128_f128 uZ; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp == 0x7FF ) { if ( sig ) { softfloat_f64UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF128UI( &commonNaN ); } else { uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); uiZ.v0 = 0; } goto uiZ; } if ( ! exp ) { if ( ! sig ) { uiZ.v64 = packToF128UI64( sign, 0, 0 ); uiZ.v0 = 0; goto uiZ; } normExpSig = softfloat_normSubnormalF64Sig( sig ); exp = normExpSig.exp - 1; sig = normExpSig.sig; } sig128 = softfloat_shortShiftLeft128( 0, sig, 60 ); uiZ.v64 = packToF128UI64( sign, exp + 0x3C00, sig128.v64 ); uiZ.v0 = sig128.v0; uiZ: uZ.ui = uiZ; return uZ.f; }
uint_fast64_t f64_to_ui64( float64_t a, uint_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftDist; #ifdef SOFTFLOAT_FAST_INT64 struct uint64_extra sigExtra; #else uint32_t extSig[3]; #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftDist = 0x433 - exp; #ifdef SOFTFLOAT_FAST_INT64 if ( shiftDist <= 0 ) { if ( shiftDist < -11 ) goto invalid; sigExtra.v = sig<<-shiftDist; sigExtra.extra = 0; } else { sigExtra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); } return softfloat_roundToUI64( sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); #else extSig[indexWord( 3, 0 )] = 0; if ( shiftDist <= 0 ) { if ( shiftDist < -11 ) goto invalid; sig <<= -shiftDist; extSig[indexWord( 3, 2 )] = sig>>32; extSig[indexWord( 3, 1 )] = sig; } else {
float16_t f64_to_f16( float64_t a ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t frac; struct commonNaN commonNaN; uint_fast16_t uiZ, frac16; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); frac = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FF ) { if ( frac ) { softfloat_f64UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF16UI( &commonNaN ); } else { uiZ = packToF16UI( sign, 0x1F, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac16 = softfloat_shortShiftRightJam64( frac, 38 ); if ( ! (exp | frac16) ) { uiZ = packToF16UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ return softfloat_roundPackToF16( sign, exp - 0x3F1, frac16 | 0x4000 ); uiZ: uZ.ui = uiZ; return uZ.f; }
uint_fast32_t f64_to_ui32_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftDist; bool sign; uint_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x433 - exp; if ( 53 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF64UI( uiA ); if ( sign || (shiftDist < 21) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && sig ? ui32_fromNaN : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig |= UINT64_C( 0x0010000000000000 ); z = sig>>shiftDist; if ( exact && ((uint_fast64_t) z<<shiftDist != sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; }
int_fast64_t f64_to_i64_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; int_fast64_t absZ; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); shiftCount = 0x433 - exp; if ( shiftCount <= 0 ) { if ( shiftCount < -10 ) { if ( uiA != packToF64UI( 1, 0x43E, 0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); if ( ! sign || ((exp == 0x7FF) && sig) ) { return INT64_C( 0x7FFFFFFFFFFFFFFF ); } } return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } sig |= UINT64_C( 0x0010000000000000 ); absZ = sig<<-shiftCount; } else { if ( 53 <= shiftCount ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } sig |= UINT64_C( 0x0010000000000000 ); absZ = sig>>shiftCount; if ( exact && (absZ<<shiftCount != sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } } return sign ? -absZ : absZ; }
int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; bool sign; int_fast32_t absZ; uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); shiftCount = 0x433 - exp; if ( 53 <= shiftCount ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } sign = signF64UI( uiA ); if ( shiftCount < 22 ) { if ( sign && (exp == 0x41E) && (sig < UINT64_C( 0x0000000000200000 )) ) { if ( exact && sig ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } } else { softfloat_raiseFlags( softfloat_flag_invalid ); if ( ! sign || ((exp == 0x7FF) && sig) ) return 0x7FFFFFFF; } return -0x7FFFFFFF - 1; } sig |= UINT64_C( 0x0010000000000000 ); absZ = sig>>shiftCount; if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ<<shiftCount != sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sign ? -absZ : absZ; }
int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t sig; bool sign; int_fast16_t shiftCount; uint_fast32_t absZ; union { uint32_t ui; int32_t i; } uZ; int_fast32_t z; uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp < 0x3FF ) { if ( exact && ( exp | sig ) ) { softfloat_raiseFlags( softfloat_flag_inexact ); } return 0; } sign = signF64UI( uiA ); if ( 0x41E < exp ) { if ( ( exp == 0x7FF ) && sig ) sign = 0; goto invalid; } sig |= UINT64_C( 0x0010000000000000 ); shiftCount = 0x433 - exp; absZ = sig>>shiftCount; uZ.ui = sign ? - absZ : absZ; z = uZ.i; if ( ( z < 0 ) != sign ) goto invalid; if ( exact && ( (uint_fast64_t) absZ<<shiftCount != sig ) ) { softfloat_raiseFlags( softfloat_flag_inexact ); } return z; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? -0x7FFFFFFF - 1 : 0x7FFFFFFF; }
uint_fast32_t f64_to_ui32( float64_t a, uint_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftCount = 0x42C - exp; if ( 0 < shiftCount ) sig = softfloat_shiftRightJam64( sig, shiftCount ); return softfloat_roundPackToUI32( sign, sig, roundingMode, exact ); }
int_fast32_t f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) if ( (exp == 0x7FF) && sig ) { #if (i32_fromNaN == i32_fromPosOverflow) sign = 0; #elif (i32_fromNaN == i32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return i32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftDist = 0x42C - exp; if ( 0 < shiftDist ) sig = softfloat_shiftRightJam64( sig, shiftDist ); return softfloat_roundPackToI32( sign, sig, roundingMode, exact ); }
uint_fast64_t f64_to_ui64_r_minMag( float64_t a, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t sig; int_fast16_t shiftCount; uint_fast64_t z; uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); shiftCount = 0x433 - exp; if ( 53 <= shiftCount ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } if ( signF64UI( uiA ) ) goto invalid; if ( shiftCount <= 0 ) { if ( shiftCount < -11 ) goto invalid; z = (sig | UINT64_C( 0x0010000000000000 ))<<-shiftCount; } else { sig |= UINT64_C( 0x0010000000000000 ); z = sig>>shiftCount; if ( exact && (uint64_t) (sig<<(-shiftCount & 63)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } } return z; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return UINT64_C( 0xFFFFFFFFFFFFFFFF ); }
uint_fast16_t f64_classify( float64_t a ) { union ui64_f64 uA; uint_fast64_t uiA; uA.f = a; uiA = uA.ui; uint_fast16_t infOrNaN = expF64UI( uiA ) == 0x7FF; uint_fast16_t subnormalOrZero = expF64UI( uiA ) == 0; bool sign = signF64UI( uiA ); return ( sign && infOrNaN && fracF64UI( uiA ) == 0 ) << 0 | ( sign && !infOrNaN && !subnormalOrZero ) << 1 | ( sign && subnormalOrZero && fracF64UI( uiA ) ) << 2 | ( sign && subnormalOrZero && fracF64UI( uiA ) == 0 ) << 3 | ( !sign && infOrNaN && fracF64UI( uiA ) == 0 ) << 7 | ( !sign && !infOrNaN && !subnormalOrZero ) << 6 | ( !sign && subnormalOrZero && fracF64UI( uiA ) ) << 5 | ( !sign && subnormalOrZero && fracF64UI( uiA ) == 0 ) << 4 | ( isNaNF64UI( uiA ) && softfloat_isSigNaNF64UI( uiA )) << 8 | ( isNaNF64UI( uiA ) && !softfloat_isSigNaNF64UI( uiA )) << 9; }
float64_t f64_div( 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; struct exp16_sig64 normExpSig; int_fast16_t expZ; uint_fast64_t sigZ; struct uint128 term, rem; uint_fast64_t 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 ) goto propagateNaN; if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; goto invalid; } goto infinity; } if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; goto zero; } if ( ! expB ) { if ( ! sigB ) { if ( ! ( expA | sigA ) ) goto invalid; softfloat_raiseFlags( softfloat_flag_infinity ); goto infinity; } normExpSig = softfloat_normSubnormalF64Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF64Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } expZ = expA - expB + 0x3FD; sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<10; sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<11; if ( sigB <= ( sigA + sigA ) ) { ++expZ; sigA >>= 1; }
float64_t f64_mul( float64_t a, float64_t b ) { union ui64_f64 uA; uint_fast64_t uiA; bool signA; int_fast16_t expA; uint_fast64_t sigA; union ui64_f64 uB; uint_fast64_t uiB; bool signB; int_fast16_t expB; uint_fast64_t sigB; bool signZ; uint_fast64_t magBits; struct exp16_sig64 normExpSig; int_fast16_t expZ; struct uint128 sigZ128; uint_fast64_t sigZ, uiZ; union ui64_f64 uZ; uA.f = a; uiA = uA.ui; signA = signF64UI( uiA ); expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF64UI( uiB ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); signZ = signA ^ signB; if ( expA == 0x7FF ) { if ( sigA || ( ( expB == 0x7FF ) && sigB ) ) goto propagateNaN; magBits = expB | sigB; goto infArg; } if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; magBits = expA | sigA; goto infArg; } if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF64Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalF64Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } expZ = expA + expB - 0x3FF; sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<10; sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<11; sigZ128 = softfloat_mul64To128( sigA, sigB ); sigZ = sigZ128.v64 | ( sigZ128.v0 != 0 ); if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { --expZ; sigZ <<= 1; } return softfloat_roundPackToF64( signZ, expZ, sigZ ); propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); goto uiZ; infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; } else { uiZ = packToF64UI( signZ, 0x7FF, 0 ); } goto uiZ; zero: uiZ = packToF64UI( signZ, 0, 0 ); uiZ: uZ.ui = uiZ; return uZ.f; }
float64_t softfloat_subMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ ) { int_fast16_t expA; uint_fast64_t sigA; int_fast16_t expB; uint_fast64_t sigB; int_fast16_t expDiff; uint_fast64_t uiZ; int_fast16_t expZ; uint_fast64_t sigZ; union ui64_f64 uZ; expA = expF64UI( uiA ); sigA = fracF64UI( uiA ); expB = expF64UI( uiB ); sigB = fracF64UI( uiB ); expDiff = expA - expB; sigA <<= 10; sigB <<= 10; if ( 0 < expDiff ) goto expABigger; if ( expDiff < 0 ) goto expBBigger; if ( expA == 0x7FF ) { if ( sigA | sigB ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; goto uiZ; } if ( ! expA ) { expA = 1; expB = 1; } if ( sigB < sigA ) goto aBigger; if ( sigA < sigB ) goto bBigger; uiZ = packToF64UI( softfloat_roundingMode == softfloat_round_min, 0, 0 ); goto uiZ; expBBigger: if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; uiZ = packToF64UI( signZ ^ 1, 0x7FF, 0 ); goto uiZ; } sigA += expA ? UINT64_C( 0x4000000000000000 ) : sigA; sigA = softfloat_shiftRightJam64( sigA, -expDiff ); sigB |= UINT64_C( 0x4000000000000000 ); bBigger: signZ ^= 1; expZ = expB; sigZ = sigB - sigA; goto normRoundPack; expABigger: if ( expA == 0x7FF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } sigB += expB ? UINT64_C( 0x4000000000000000 ) : sigB; sigB = softfloat_shiftRightJam64( sigB, expDiff ); sigA |= UINT64_C( 0x4000000000000000 ); aBigger: expZ = expA; sigZ = sigA - sigB; normRoundPack: return softfloat_normRoundPackToF64( signZ, expZ - 1, sigZ ); propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); uiZ: uZ.ui = uiZ; return uZ.f; }
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_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_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 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_mulAddF64( uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) { bool signA; int_fast16_t expA; uint64_t sigA; bool signB; int_fast16_t expB; uint64_t sigB; bool signC; int_fast16_t expC; uint64_t sigC; bool signZ; uint64_t magBits, uiZ; struct exp16_sig64 normExpSig; int_fast16_t expZ; uint32_t sig128Z[4]; uint64_t sigZ; int_fast16_t shiftCount, expDiff; uint32_t sig128C[4]; 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 ))<<11; softfloat_mul64To128M( sigA, sigB, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; shiftCount = 0; if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { --expZ; shiftCount = -1; } if ( ! expC ) { if ( ! sigC ) { if ( shiftCount ) sigZ <<= 1; goto sigZ; } normExpSig = softfloat_normSubnormalF64Sig( sigC ); expC = normExpSig.exp; sigC = normExpSig.sig; } sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<10; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expZ - expC; if ( expDiff < 0 ) { expZ = expC; if ( (signZ == signC) || (expDiff < -1) ) { shiftCount -= expDiff; if ( shiftCount) { sigZ = softfloat_shiftRightJam64( sigZ, shiftCount ); } } else { if ( ! shiftCount ) { softfloat_shortShiftRight128M( sig128Z, 1, sig128Z ); } } } else { if ( shiftCount ) softfloat_add128M( sig128Z, sig128Z, sig128Z ); if ( ! expDiff ) { sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; } else { sig128C[indexWord( 4, 3 )] = sigC>>32; sig128C[indexWord( 4, 2 )] = sigC; sig128C[indexWord( 4, 1 )] = 0; sig128C[indexWord( 4, 0 )] = 0; softfloat_shiftRightJam128M( sig128C, expDiff, sig128C ); } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( signZ == signC ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff <= 0 ) { sigZ += sigC; } else { softfloat_add128M( sig128Z, sig128C, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; } if ( sigZ & UINT64_C( 0x8000000000000000 ) ) { ++expZ; sigZ = softfloat_shortShiftRightJam64( sigZ, 1 ); } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff < 0 ) { signZ = signC; if ( expDiff < -1 ) { sigZ = sigC - sigZ; if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) { sigZ = (sigZ - 1) | 1; } if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { --expZ; sigZ <<= 1; } goto roundPack; } else { sig128C[indexWord( 4, 3 )] = sigC>>32; sig128C[indexWord( 4, 2 )] = sigC; sig128C[indexWord( 4, 1 )] = 0; sig128C[indexWord( 4, 0 )] = 0; softfloat_sub128M( sig128C, sig128Z, sig128Z ); } } else if ( ! expDiff ) {