/* math2.c (emx+gcc) */

#include <math.h>
#include <float.h>
#include <assert.h>

struct
{
  unsigned long i32;
  int fpclass;
} testvec_float[] =
  {
    { 0x00000000, FP_ZERO },
    { 0x00000001, FP_SUBNORMAL },
    { 0x007fffff, FP_SUBNORMAL },
    { 0x00800000, FP_NORMAL },
    { 0x7f7fffff, FP_NORMAL },
    { 0x7f800000, FP_INFINITE },
    { 0x7f800001, FP_NAN },
    { 0x7fffffff, FP_NAN }
  };

struct
{
  unsigned long long i64;
  int fpclass;
} testvec_double[] =
  {
    { 0x0000000000000000ULL, FP_ZERO },
    { 0x0000000000000001ULL, FP_SUBNORMAL },
    { 0x000fffffffffffffULL, FP_SUBNORMAL },
    { 0x0010000000000000ULL, FP_NORMAL },
    { 0x7fefffffffffffffULL, FP_NORMAL },
    { 0x7ff0000000000000ULL, FP_INFINITE },
    { 0x7ff0000000000001ULL, FP_NAN },
    { 0x7fffffffffffffffULL, FP_NAN }
  };

struct
{
  unsigned short i16;
  unsigned long long i64;
  int fpclass;
} testvec_long_double[] =
  {
    { 0x0000, 0x0000000000000000ULL, FP_ZERO },
    { 0x0000, 0x0000000000000001ULL, FP_SUBNORMAL },
    { 0x0000, 0x7fffffffffffffffULL, FP_SUBNORMAL },
    { 0x0000, 0x8000000000000000ULL, FP_SUBNORMAL }, /* pseudo-denormal */
    { 0x0000, 0xffffffffffffffffULL, FP_SUBNORMAL }, /* pseudo-denormal */
    { 0x0001, 0x0000000000000000ULL, FP_NAN }, /* unnormal */
    { 0x0001, 0x7fffffffffffffffULL, FP_NAN }, /* unnormal */
    { 0x0001, 0x8000000000000000ULL, FP_NORMAL },
    { 0x7ffd, 0xffffffffffffffffULL, FP_NORMAL },
    { 0x7ffe, 0x0000000000000000ULL, FP_NAN }, /* unnormal */
    { 0x7ffe, 0x7fffffffffffffffULL, FP_NAN }, /* unnormal */
    { 0x7ffe, 0x8000000000000000ULL, FP_NORMAL },
    { 0x7ffe, 0xffffffffffffffffULL, FP_NORMAL },
    { 0x7fff, 0x0000000000000000ULL, FP_NAN }, /* pseudo-infinity */
    { 0x7fff, 0x0000000000000001ULL, FP_NAN }, /* pseudo-NaN */
    { 0x7fff, 0x7fffffffffffffffULL, FP_NAN }, /* pseudo-NaN */
    { 0x7fff, 0x8000000000000000ULL, FP_INFINITE },
    { 0x7fff, 0x8000000000000001ULL, FP_NAN }, /* NaN */
    { 0x7fff, 0xffffffffffffffffULL, FP_NAN }
  };

int main (void)
{
  union
  {
    float f;
    double d;
    long double l;
    unsigned long i32;
    unsigned long long i64;
    struct
    {
      unsigned long long i64;
      unsigned short i16;
    } i80;
  } x;
  int i, c;

  assert (fpclassify (0.0F) == FP_ZERO);
  assert (fpclassify (-0.0F) == FP_ZERO);
  assert (fpclassify (1e-39F) == FP_SUBNORMAL);
  assert (fpclassify (-1e-39F) == FP_SUBNORMAL);
  assert (fpclassify (FLT_MIN/2) == FP_SUBNORMAL);
  assert (fpclassify (-FLT_MIN/2) == FP_SUBNORMAL);
  assert (fpclassify (FLT_MIN) == FP_NORMAL);
  assert (fpclassify (-FLT_MIN) == FP_NORMAL);
  assert (fpclassify (17.0F) == FP_NORMAL);
  assert (fpclassify (-17.0F) == FP_NORMAL);
  assert (fpclassify (FLT_MAX) == FP_NORMAL);
  assert (fpclassify (-FLT_MAX) == FP_NORMAL);
  assert (fpclassify (1.0F/0.0F) == FP_INFINITE);
  assert (fpclassify (-1.0F/0.0F) == FP_INFINITE);
  assert (fpclassify (0.0F/0.0F) == FP_NAN);

  for (i = 0; i < sizeof (testvec_float) / sizeof (testvec_float[0]); ++i)
    {
      c = testvec_float[i].fpclass;
      x.i32 = testvec_float[i].i32;
      assert (fpclassify (x.f) == c);
      assert (signbit (x.f) == 0);
      assert (!isfinite (x.f) == (c == FP_INFINITE || c == FP_NAN));
      assert (!isnormal (x.f) == (c != FP_NORMAL));
      assert (!isnan (x.f) == (c != FP_NAN));
      x.i32 = testvec_float[i].i32 | 0x80000000;
      assert (fpclassify (x.f) == c);
      assert (signbit (x.f) == 1);
      assert (!isfinite (x.f) == (c == FP_INFINITE || c == FP_NAN));
      assert (!isnormal (x.f) == (c != FP_NORMAL));
      assert (!isnan (x.f) == (c != FP_NAN));
    }

  assert (fpclassify (0.0) == FP_ZERO);
  assert (fpclassify (-0.0) == FP_ZERO);
  assert (fpclassify (1e-309) == FP_SUBNORMAL);
  assert (fpclassify (-1e-309) == FP_SUBNORMAL);
  assert (fpclassify (DBL_MIN/2) == FP_SUBNORMAL);
  assert (fpclassify (-DBL_MIN/2) == FP_SUBNORMAL);
  assert (fpclassify (DBL_MIN) == FP_NORMAL);
  assert (fpclassify (-DBL_MIN) == FP_NORMAL);
  assert (fpclassify (17.0) == FP_NORMAL);
  assert (fpclassify (-17.0) == FP_NORMAL);
  assert (fpclassify (DBL_MAX) == FP_NORMAL);
  assert (fpclassify (-DBL_MAX) == FP_NORMAL);
  assert (fpclassify (1.0/0.0) == FP_INFINITE);
  assert (fpclassify (-1.0/0.0) == FP_INFINITE);
  assert (fpclassify (0.0/0.0) == FP_NAN);

  for (i = 0; i < sizeof (testvec_double) / sizeof (testvec_double[0]); ++i)
    {
      c = testvec_double[i].fpclass;
      x.i64 = testvec_double[i].i64;
      assert (fpclassify (x.d) == c);
      assert (signbit (x.d) == 0);
      assert (!isfinite (x.d) == (c == FP_INFINITE || c == FP_NAN));
      assert (!isnormal (x.d) == (c != FP_NORMAL));
      assert (!isnan (x.d) == (c != FP_NAN));
      x.i64 |= 0x8000000000000000ULL;
      assert (fpclassify (x.d) == c);
      assert (signbit (x.d) == 1);
      assert (!isfinite (x.d) == (c == FP_INFINITE || c == FP_NAN));
      assert (!isnormal (x.d) == (c != FP_NORMAL));
      assert (!isnan (x.d) == (c != FP_NAN));
    }

  assert (fpclassify (0.0L) == FP_ZERO);
  assert (fpclassify (-0.0L) == FP_ZERO);
  assert (fpclassify (1e-4940L) == FP_SUBNORMAL);
  assert (fpclassify (-1e-4940L) == FP_SUBNORMAL);
  assert (fpclassify (DBL_MIN/2) == FP_SUBNORMAL);
  assert (fpclassify (-DBL_MIN/2) == FP_SUBNORMAL);
  assert (fpclassify (DBL_MIN) == FP_NORMAL);
  assert (fpclassify (-DBL_MIN) == FP_NORMAL);
  assert (fpclassify (17.0L) == FP_NORMAL);
  assert (fpclassify (-17.0L) == FP_NORMAL);
  assert (fpclassify (DBL_MAX) == FP_NORMAL);
  assert (fpclassify (-DBL_MAX) == FP_NORMAL);
  assert (fpclassify (1.0L/0.0L) == FP_INFINITE);
  assert (fpclassify (-1.0L/0.0L) == FP_INFINITE);
  assert (fpclassify (0.0L/0.0L) == FP_NAN);

  for (i = 0;
       i < sizeof (testvec_long_double) / sizeof (testvec_long_double[0]); ++i)
    {
      c = testvec_long_double[i].fpclass;
      x.i80.i64 = testvec_long_double[i].i64;
      x.i80.i16 = testvec_long_double[i].i16;
      assert (fpclassify (x.l) == c);
      assert (signbit (x.l) == 0);
      assert (!isfinite (x.l) == (c == FP_INFINITE || c == FP_NAN));
      assert (!isnormal (x.l) == (c != FP_NORMAL));
      assert (!isnan (x.l) == (c != FP_NAN));
      x.i80.i16 |= 0x8000;
      assert (fpclassify (x.l) == c);
      assert (signbit (x.l) == 1);
      assert (!isfinite (x.l) == (c == FP_INFINITE || c == FP_NAN));
      assert (!isnormal (x.l) == (c != FP_NORMAL));
      assert (!isnan (x.l) == (c != FP_NAN));
    }

  return 0;
}
