/***********************************************************************
Check whether IEEE 754 signed zero is correctly supported.
[09-May-2001]
***********************************************************************/

#if defined(HAVE_LONG_DOUBLE)
typedef long double LONG_DOUBLE;
#else
typedef double LONG_DOUBLE;
#endif

#include <stdio.h>
#include <stdlib.h>
#include "args.h"

typedef union
{
    double f;
    unsigned i[2];
} D;

#if defined(HAVE_LONG_DOUBLE)
typedef union
{
    LONG_DOUBLE f;
    unsigned i[4];
} E;
#endif

typedef union
{
    float f;
    unsigned i[1];
} S;

static const char* expect_signed ARGS((unsigned int e));
static const char* expect_unsigned ARGS((unsigned int e));

int
main(VOID_ARG)
{
    D d;
#if defined(HAVE_LONG_DOUBLE)
    E e;
#endif
    S s;
    int top;

    /******************************************************************/

    (void)printf("\nZero handling in single-precision IEEE 754 arithmetic:\n");
    (void)printf("sizeof(float) = %u\n", (unsigned int)sizeof(float));
    top = 0;

    s.f = (float)0.0;
    (void)printf("+zero is %s\n", expect_unsigned(s.i[top]));

    s.f = -(float)0.0;
    (void)printf("-zero is %s\n", expect_signed(s.i[top]));

    s.f = (float)0.0 - (float)0.0;
    (void)printf("0 - 0 is %s\n", expect_unsigned(s.i[top]));

    s.f = (-(float)0.0) - (float)0.0;
    (void)printf("(-0) - (+0) is %s\n", expect_signed(s.i[top]));

    s.f = (float)0.0;
    s.f *= (float)1.0;
    (void)printf("(+1)*(0) is %s\n", expect_unsigned(s.i[top]));

    s.f = (float)0.0;
    s.f *= -(float)1.0;
    (void)printf("(-1)*(0) is %s\n", expect_signed(s.i[top]));

    /******************************************************************/

    (void)printf("\nZero handling in double-precision IEEE 754 arithmetic:\n");
    (void)printf("sizeof(double) = %u\n", (unsigned int)sizeof(double));
    d.f = 1.0;
    top = (d.i[0] == 0) ? 1 : 0;

    d.f = (double)0.0;
    (void)printf("+zero is %s\n", expect_unsigned(d.i[top]));

    d.f = (double)-0.0;
    (void)printf("-zero is %s\n", expect_signed(d.i[top]));

    d.f = (double)0.0 - (double)0.0;
    (void)printf("0 - 0 is %s\n", expect_unsigned(d.i[top]));

    d.f = ((double)-0.0) - (double)0.0;
    (void)printf("(-0) - (+0) is %s\n", expect_signed(d.i[top]));

    d.f = (double)0.0;
    d.f *= (double)1.0;
    (void)printf("(+1)*(0) is %s\n", expect_unsigned(d.i[top]));

    d.f = (double)0.0;
    d.f *= (double)-1.0;
    (void)printf("(-1)*(0) is %s\n", expect_signed(d.i[top]));

    /******************************************************************/

#if defined(HAVE_LONG_DOUBLE)
    (void)printf("\nZero handling in extended-precision IEEE 754 arithmetic:\n");
    (void)printf("sizeof(long double) = %u\n", (unsigned int)sizeof(LONG_DOUBLE));
    e.f = (LONG_DOUBLE)1.0;
    if (sizeof(LONG_DOUBLE) == 16u)
	top = (e.i[0] == 0) ? 3 : 0;
    else if (sizeof(LONG_DOUBLE) == 12u)
	top = (e.i[0] == 0) ? 2 : 0;
    else if (sizeof(LONG_DOUBLE) == 8u)
	top = (e.i[0] == 0) ? 1 : 0;
    else
    {
	printf("WARNING: unexpected size of extended-precision data type\n");
	top = 0;
    }

    e.f = (LONG_DOUBLE)0.0;
    (void)printf("+zero is %s\n", expect_unsigned(e.i[top]));

    e.f = -(LONG_DOUBLE)0.0;
    (void)printf("-zero is %s\n", expect_signed(e.i[top]));

    e.f = (LONG_DOUBLE)0.0 - (LONG_DOUBLE)0.0;
    (void)printf("0 - 0 is %s\n", expect_unsigned(e.i[top]));

    e.f = (-(LONG_DOUBLE)0.0) - (LONG_DOUBLE)0.0;
    (void)printf("(-0) - (+0) is %s\n", expect_signed(e.i[top]));

    e.f = (LONG_DOUBLE)0.0;
    e.f *= (LONG_DOUBLE)1.0;
    (void)printf("(+1)*(0) is %s\n", expect_unsigned(e.i[top]));

    e.f = (LONG_DOUBLE)0.0;
    e.f *= -(LONG_DOUBLE)1.0;
    (void)printf("(-1)*(0) is %s\n", expect_signed(e.i[top]));
#endif

    /******************************************************************/

    return (EXIT_SUCCESS);
}

#if STDC
static const char*
expect_signed(unsigned int e)
#else
static const char*
expect_signed(e)
unsigned int e;
#endif
{
    return ((e == 0x80000000) ? "  signed\t\t(CORRECT)" : "unsigned\t\t(WRONG)");
}

#if STDC
static const char*
expect_unsigned(unsigned int e)
#else
static const char*
expect_unsigned(e)
unsigned int e;
#endif
{
    return ((e == 0x00000000) ? "unsigned\t\t(CORRECT)" : "  signed\t\t(WRONG)");
}
