float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM)

{

    flag aSign;

    int_fast16_t aExp;

    uint32_t aSig;

    uint32_t mask;

    uint32_t increment;

    int8 roundingMode;

    a = float32_squash_input_denormal(a STATUS_VAR);



    aSig = extractFloat32Frac( a );

    aExp = extractFloat32Exp( a );

    aSign = extractFloat32Sign( a );

    if ( aExp == 0xFF ) {

        if (aSig) {

            /* Input is a NaN */

            float16 r = commonNaNToFloat16( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR );

            if (!ieee) {

                return packFloat16(aSign, 0, 0);

            }

            return r;

        }

        /* Infinity */

        if (!ieee) {

            float_raise(float_flag_invalid STATUS_VAR);

            return packFloat16(aSign, 0x1f, 0x3ff);

        }

        return packFloat16(aSign, 0x1f, 0);

    }

    if (aExp == 0 && aSig == 0) {

        return packFloat16(aSign, 0, 0);

    }

    /* Decimal point between bits 22 and 23.  */

    aSig |= 0x00800000;

    aExp -= 0x7f;

    if (aExp < -14) {

        mask = 0x00ffffff;

        if (aExp >= -24) {

            mask >>= 25 + aExp;

        }

    } else {

        mask = 0x00001fff;

    }

    if (aSig & mask) {

        float_raise( float_flag_underflow STATUS_VAR );

        roundingMode = STATUS(float_rounding_mode);

        switch (roundingMode) {

        case float_round_nearest_even:

            increment = (mask + 1) >> 1;

            if ((aSig & mask) == increment) {

                increment = aSig & (increment << 1);

            }

            break;

        case float_round_up:

            increment = aSign ? 0 : mask;

            break;

        case float_round_down:

            increment = aSign ? mask : 0;

            break;

        default: /* round_to_zero */

            increment = 0;

            break;

        }

        aSig += increment;

        if (aSig >= 0x01000000) {

            aSig >>= 1;

            aExp++;

        }

    } else if (aExp < -14

          && STATUS(float_detect_tininess) == float_tininess_before_rounding) {

        float_raise( float_flag_underflow STATUS_VAR);

    }



    if (ieee) {

        if (aExp > 15) {

            float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR);

            return packFloat16(aSign, 0x1f, 0);

        }

    } else {

        if (aExp > 16) {

            float_raise(float_flag_invalid | float_flag_inexact STATUS_VAR);

            return packFloat16(aSign, 0x1f, 0x3ff);

        }

    }

    if (aExp < -24) {

        return packFloat16(aSign, 0, 0);

    }

    if (aExp < -14) {

        aSig >>= -14 - aExp;

        aExp = -14;

    }

    return packFloat16(aSign, aExp + 14, aSig >> 13);

}
