float16_t f16_rem( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; bool signA; int_fast8_t expA; uint_fast16_t sigA; union ui16_f16 uB; uint_fast16_t uiB; int_fast8_t expB; uint_fast16_t sigB; struct exp8_sig16 normExpSig; uint16_t rem; int_fast8_t expDiff; uint_fast16_t q; uint32_t recip32, q32; uint16_t altRem, meanRem; bool signRem; uint_fast16_t uiZ; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF16UI( uiA ); expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); uB.f = b; uiB = uB.ui; expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; goto invalid; } if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN; return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expB ) { if ( ! sigB ) goto invalid; normExpSig = softfloat_normSubnormalF16Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } if ( ! expA ) { if ( ! sigA ) return a; normExpSig = softfloat_normSubnormalF16Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ rem = sigA | 0x0400; sigB |= 0x0400; expDiff = expA - expB; if ( expDiff < 1 ) { if ( expDiff < -1 ) return a; sigB <<= 3; if ( expDiff ) { rem <<= 2; q = 0; } else { rem <<= 3; q = (sigB <= rem); if ( q ) rem -= sigB; } } else { recip32 = softfloat_approxRecip32_1( (uint_fast32_t) sigB<<21 ); /*-------------------------------------------------------------------- | Changing the shift of `rem' here requires also changing the initial | subtraction from `expDiff'. *--------------------------------------------------------------------*/ rem <<= 4; expDiff -= 31; /*-------------------------------------------------------------------- | The scale of `sigB' affects how many bits are obtained during each | cycle of the loop. Currently this is 29 bits per loop iteration, | which is believed to be the maximum possible. *--------------------------------------------------------------------*/ sigB <<= 3; for (;;) { q32 = (rem * (uint_fast64_t) recip32)>>16; if ( expDiff < 0 ) break; rem = -((uint_fast16_t) q32 * sigB); expDiff -= 29; } /*-------------------------------------------------------------------- | (`expDiff' cannot be less than -30 here.) *--------------------------------------------------------------------*/ q32 >>= ~expDiff & 31; q = q32; rem = (rem<<(expDiff + 30)) - q * sigB; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ do { altRem = rem; ++q; rem -= sigB; } while ( ! (rem & 0x8000) ); meanRem = rem + altRem; if ( (meanRem & 0x8000) || (! meanRem && (q & 1)) ) rem = altRem; signRem = signA; if ( 0x8000 <= rem ) { signRem = ! signRem; rem = -rem; } return softfloat_normRoundPackToF16( signRem, expB, rem ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); goto uiZ; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF16UI; uiZ: uZ.ui = uiZ; return uZ.f; }
float16_t f16_mul( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; bool signA; int_fast8_t expA; uint_fast16_t sigA; union ui16_f16 uB; uint_fast16_t uiB; bool signB; int_fast8_t expB; uint_fast16_t sigB; bool signZ; uint_fast16_t magBits; struct exp8_sig16 normExpSig; int_fast8_t expZ; uint_fast32_t sig32Z; uint_fast16_t sigZ, uiZ; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF16UI( uiA ); expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF16UI( uiB ); expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; magBits = expB | sigB; goto infArg; } if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN; magBits = expA | sigA; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF16Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalF16Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0xF; sigA = (sigA | 0x0400)<<4; sigB = (sigB | 0x0400)<<5; sig32Z = (uint_fast32_t) sigA * sigB; sigZ = sig32Z>>16; if ( sig32Z & 0xFFFF ) sigZ |= 1; if ( sigZ < 0x4000 ) { --expZ; sigZ <<= 1; } return softfloat_roundPackToF16( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF16UI; } else { uiZ = packToF16UI( signZ, 0x1F, 0 ); } goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ = packToF16UI( signZ, 0, 0 ); uiZ: uZ.ui = uiZ; return uZ.f; }