#ifdef KR_headers
#define Volatile /* volatile */
#else
#define Volatile volatile
#endif

#undef No_Prec

/*
	Liberally stolen from David Gay's ifdef Symantec section
	Again, most remaining int's can probably be made into short's
	DOS - Not sure whether Undef_Compilers should be def'd,
	nor whether __FPCE_IEEE__ should be undef'd, but if DG likes
	it then its probably right
*/
#ifdef DOS
#include "float.h"
#define swapRM(x) _control87(x,MCW_RC)
#define Round_Down RC_DOWN
#define Round_Near RC_NEAR
#define Round_Up RC_UP
#define Round_Zero RC_CHOP
#define set_prec(x) _control87(MCW_EM | x, MCW_EM | MCW_PC)
void generic_precision(void);
static int get_significand(void);
void retrospective(void);
#define Undef_Compilers
#undef __FPCE_IEEE__
#endif

#ifdef SYMANTEC
#include "float.h"
#define swapRM(x) _control87(x,_MCW_RC)
#define Round_Down	_RC_DOWN
#define Round_Near	_RC_NEAR
#define Round_Up	_RC_UP
#define Round_Zero	_RC_CHOP
#define PC_24 _PC_24
#define PC_53 _PC_53
#define PC_64 _PC_64
#define set_prec(x) _control87(_MCW_EM | x, _MCW_EM | _MCW_PC)
#define Undef_Compilers
#undef __FPCE_IEEE__
#endif

#ifdef __FPCE_IEEE__
#include "fenv.h"
#define swapRM(x) fesetround(x)
#define Round_Down	FE_DOWNWARD
#define Round_Near	FE_TONEAREST
#define Round_Up	FE_UPWARD
#define Round_Zero	FE_TOWARDZERO
#define Undef_Compilers
#define No_Prec
#endif

#ifdef __hpux
#include "math.h"
#define swapRM(x) fpsetround(x)
#define Round_Down	FP_RM
#define Round_Near	FP_RN
#define Round_Up	FP_RP
#define Round_Zero	FP_RZ
#define Undef_Compilers
#define No_Prec
#endif

#ifdef _nst
#undef High_C
#define High_C
#endif
#ifdef High_C
#include "ieeefp.h"
#define swapRM(x) fpsetround(x)
#define Round_Down	FP_RM
#define Round_Near	FP_RN
#define Round_Up	FP_RP
#define Round_Zero	FP_RZ
#define Undef_Compilers
#endif

#ifdef Undef_Compilers
#undef sgi
#undef mips
#undef _AIX
#undef sun
#undef SVS_C
#undef __hpux
#undef High_C
#undef _nst
#endif

#ifdef mips
#undef sgi
#define sgi
#endif

#ifdef sgi
#include "sys/fpu.h"
#define Round_Down	ROUND_TO_MINUS_INFINITY
#define Round_Near	ROUND_TO_NEAREST
#define Round_Up	ROUND_TO_PLUS_INFINITY
#define Round_Zero	ROUND_TO_ZERO
#define No_Prec
#endif

#ifdef _AIX
#include "float.h"
#define swapRM fp_swap_rnd
#define Round_Down	FP_RND_RM
#define Round_Near	FP_RND_RN
#define Round_Up	FP_RND_RP
#define Round_Zero	FP_RND_RZ
#define No_Prec
#endif

#if defined(sun) || defined(SUN_IEEE)
#include "math.h"
#include "sys/ieeefp.h"

static char	direction[] = "direction",
		nearest[] = "nearest",
		negative[] = "negative",
		positive[] = "positive",
		tozero[] = "tozero",
		set[] = "set";
#define swapRM(x) ieee_flags(set, direction, x, 0)
#define Round_Down	negative
#define Round_Near	nearest
#define Round_Up	positive
#define Round_Zero	tozero
#define PC_24		"single"
#define PC_53		"double"
#define PC_64		"extended"
#define set_prec(x)	{ char *pc; ieee_flags("set", "precision", x, &pc); }
#endif

#ifdef SVS_C
#include "float.h"
#define swapRM(x) _control87(x, MCW_RC)
#define Round_Down	RC_DOWN
#define Round_Near	RC_NEAR
#define Round_Up	RC_UP
#define Round_Zero	RC_CHOP
#define set_prec(x) _control87(MCW_EM | x, MCW_EM | MCW_PC)
#endif

#ifdef __alpha
#include "machine/fpu.h"
#define swapRM(x) fesetround(x)
#define Round_Down	FE_DOWNWARD
#define Round_Near	FE_TONEAREST
#define Round_Up	FE_UPWARD
#define Round_Zero	FE_ZERO	/*???*/
#define No_Prec
#endif

#include "ucbtest.h"

#ifdef DOS
long            ntests=0L;		/* number of test iterations to perform */
#else
int             ntests=0;		/* number of test iterations to perform */
#endif

int             significand_length;	/* length of significand in bits */

void
round_nearest()
{				/* set rounding direction to nearest */
	swapRM(Round_Near);
}

void
round_positive()
{				/* set rounding direction to +inf */
	swapRM(Round_Up);
}

void
round_zero()
{				/* set rounding direction toward zero */
	swapRM(Round_Zero);
}

#ifdef DOS
void generic_precision(void)
#else
void
generic_precision()
#endif
{
#ifdef No_Prec				/* set extended precision to GENERIC */
#ifndef DOUBLE
	fprintf(stderr,
		"Can't (don't know how to) change rounding precision!\n");
	/*exit(1);*/
#endif
#else
#ifdef FLOAT
#define Prec PC_24
#else
#ifdef LONGDOUBLE
#define Prec PC_64
#else
#define Prec PC_53
#endif
#endif
	set_prec(Prec);
#endif
}

#ifdef DOS
void retrospective(void)
#else
void
retrospective()
#endif
{				/* sun IEEE retrospective messages */
#ifdef SUN_IEEE
	char           *pc;

	(void) ieee_flags("set", "precision", "extended", &pc);
	(void) ieee_retrospective_();
#endif
}

#ifdef DOS
static int get_significand(void)
#else
static int
get_significand()
#endif
{				/* get number of significant bits */
	int             it;
#ifdef __STDC__
	volatile
#endif
		GENERIC b, t;

	it = 0;
	b = ONE;
	do {
		it++;
		b += b;
		t = b + ONE;
		t -= b;
		t -= ONE;
	} while (t == ZERO);
	return it;
}


void
begin(file, line)
	char           *file;
	int             line;
{

	printf(" ucbtest BEGIN in %s at line %d \n", file, line);
	generic_precision();
	significand_length = get_significand();
	if (ntests < 1L)  /* DOS added L */
 		ntests = NTESTS;
	if (significand_length > 64)
		ntests /= 100L;  /* DOS added L */
	/* SPARC quad precision is slowly implemented in software */
	printf(" %ld tests on %s with %d significant bits \n",ntests,GENERIC_STRING,
			  significand_length); /* DOS %d to %ld change */
}

void
ucbend(file, line)
	char           *file;
	int             line;
{

#ifdef DOS
	retrospective();
#else
	retrospective;
#endif

	printf(" ucbtest END   in %s at line %d for %s \n",
			 file, line, GENERIC_STRING);
	exit(0);
}

void
failure(file, line)
	char           *file;
	int             line;
{

	printf(" ucbtest FAIL  in %s at line %d for %s \n",
			 file, line, GENERIC_STRING);
	exit(42);
}
