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

/* Test nextafter() and copysign(). */

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

#define STR2(x) #x
#define STR(x) STR2(x)

#include STR(HEADER)

static struct
{
  unsigned long x;
  unsigned long y;
  unsigned long z;
  int ex;
} testvec_float[] =
  {
#include VEC_S
  };

static struct
{
  unsigned long long x;
  unsigned long long y;
  unsigned long long z;
  int ex;
} testvec_double[] =
  {
#include VEC_D
  };


struct i_long_double
{
  unsigned long long i64;
  unsigned short i16;
};

static struct
{
  struct i_long_double x;
  struct i_long_double y;
  struct i_long_double z;
  int ex;
} testvec_long_double[] =
  {
#include VEC_X
};


static void print_float (float x)
{
  int i;

  for (i = 3; i >= 0; --i)
    printf ("%.2x", ((unsigned char *)&x)[i]);
}


static void print_double (double x)
{
  int i;

  for (i = 7; i >= 0; --i)
    printf ("%.2x", ((unsigned char *)&x)[i]);
}


static void print_long_double (long double x)
{
  int i;

  for (i = 9; i >= 0; --i)
    printf ("%.2x", ((unsigned char *)&x)[i]);
}


int main (void)
{
  int i, errors, ex;
  float fx, fy, fz, ft;
  double dx, dy, dz, dt;
  long double lx, ly, lz, lt;

  errors = 0;

  for (i = 0; i < sizeof (testvec_float) / sizeof (testvec_float[0]); ++i)
    {
      fx = *(float *)&testvec_float[i].x;
      fy = *(float *)&testvec_float[i].y;
      fz = *(float *)&testvec_float[i].z;
      _clear87 ();
      ft = FUT_S (fx, fy);
      ex = _status87 () & 0x3f & ~SW_DENORMAL;
      if (memcmp (&ft, &fz, 4) != 0 || ex != testvec_float[i].ex)
        {
          printf ("%s() failed for i=%d:\n  x=0x", STR (FUT_S), i);
          print_float (fx);
          printf ("\n  y=0x");
          print_float (fy);
          printf ("\n  z=0x");
          print_float (fz);
          printf (" (0x%.4x)\n  t=0x", testvec_float[i].ex);
          print_float (ft);
          printf (" (0x%.4x)\n", ex);
          ++errors;
        }
    }

  for (i = 0; i < sizeof (testvec_double) / sizeof (testvec_double[0]); ++i)
    {
      dx = *(double *)&testvec_double[i].x;
      dy = *(double *)&testvec_double[i].y;
      dz = *(double *)&testvec_double[i].z;
      _clear87 ();
      dt = FUT_D (dx, dy);
      ex = _status87 () & 0x3f & ~SW_DENORMAL;
      if (memcmp (&dt, &dz, 8) != 0 || ex != testvec_double[i].ex)
        {
          printf ("%s() failed for i=%d (double):\n  x=0x", STR (FUT_D), i);
          print_double (dx);
          printf ("\n  y=0x");
          print_double (dy);
          printf ("\n  z=0x");
          print_double (dz);
          printf (" (0x%.4x)\n  t=0x", testvec_double[i].ex);
          print_double (dt);
          printf (" (0x%.4x)\n", ex);
          ++errors;
        }
    }

  for (i = 0;
       i < sizeof (testvec_long_double) / sizeof (testvec_long_double[0]); ++i)
    {
      lx = *(long double *)&testvec_long_double[i].x;
      ly = *(long double *)&testvec_long_double[i].y;
      lz = *(long double *)&testvec_long_double[i].z;
      _clear87 ();
      lt = FUT_X (lx, ly);
      ex = _status87 () & 0x3f & ~SW_DENORMAL;
      if (memcmp (&lt, &lz, 10) != 0 || ex != testvec_long_double[i].ex)
        {
          printf ("%s failed for i=%d (long double):\n  x=0x", STR (FUT_X), i);
          print_long_double (lx);
          printf ("\n  y=0x");
          print_long_double (ly);
          printf ("\n  z=0x");
          print_long_double (lz);
          printf (" (0x%.4x)\n  t=0x", testvec_long_double[i].ex);
          print_long_double (lt);
          printf (" (0x%.4x)\n", ex);
          ++errors;
        }
    }

  if (errors != 0)
    {
      printf ("Total errors: %d\n", errors);
      return 2;
    }
  return 0;
}
