#define _GNU_SOURCE
#include <fenv.h>    /* fedisableexcept() */
#include <float.h>   /* DBL_MIN */
#include <assert.h>  /* assert() */
#include <math.h>    /* isinf() */

void test_overflow(void)
{
    /* FE_OVERFLOW: The overflow exception occurs when a result has to be
       represented as a floating-point number, but has (much) larger absolute
       value than the largest (finite) floating-point number that is
       representable. */
    volatile double x = DBL_MAX;
    volatile double y = (x + x);
    assert(isinf(y));
    assert(copysign(1.0, y) == 1.0);
}

void test_underflow(void)
{
    /* FE_UNDERFLOW: The underflow exception occurs when a result has to be
       represented as a floating-point number, but has smaller absolute value
       than the smallest positive normalized floating-point number (and would
       lose much accuracy when represented as a denormalized number).

       Note: DBL_MIN is the normalized minimum. */
    volatile double x = DBL_MIN;
    volatile double y = (x * x);
    assert(y == 0.0);
}

void test_invalid(void)
{
    /* FE_INVALID: the invalid exception occurs when there is no well-defined
       result for an operation, as for 0/0 or infinity - infinity,
       or sqrt(-1). */
    volatile double x = 0.0;
    volatile double y = x / x;
    assert(isnan(y));
}

int main()
{
#if 0
    feenableexcept(FE_OVERFLOW);
#else
    fedisableexcept(FE_OVERFLOW);
#endif
#if 0
    feenableexcept(FE_UNDERFLOW);
#else
    fedisableexcept(FE_UNDERFLOW);
#endif
#if 0
    feenableexcept(FE_INVALID);
#else
    fedisableexcept(FE_INVALID);
#endif
    test_overflow();
    test_underflow();
    test_invalid();
    return 0;
}
