
#include "ucbtest.h"

#undef No_Prec
#undef Cant_Prec

#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);
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 linux
#include <fpu_control.h>
#define Round_Down	_FPU_RC_DOWN
#define Round_Near	_FPU_RC_NEAREST
#define Round_Up	_FPU_RC_UP
#define Round_Zero	_FPU_RC_ZERO
#define PC_24	_FPU_SINGLE
#define PC_53	_FPU_DOUBLE
#define PC_64	_FPU_EXTENDED
/* Note this library function sets both the precision and rounding mode.  */
#ifdef SP
#define swapRM(x) \
__setfpucw((unsigned short) (x | 0x107f | PC_24))
#else
#ifdef DP
#define swapRM(x) \
__setfpucw((unsigned short) (x | 0x107f | PC_53))
#else
#define swapRM(x) \
__setfpucw((unsigned short) (x | 0x107f | PC_64))
#endif
#endif
/* This sets the precision but also sets rounding to nearest.  */
#define set_prec(x) __setfpucw((unsigned short) (x | 0x107f))
#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 Cant_Prec
#endif

#if defined(__hpux) && !defined(sunpro_version)
#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 _AIX
#undef sun
#undef SVS_C
#undef __hpux
#undef High_C
#undef _nst
#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

/* DECstation 3000.
   In the shell script compilation options put -D_POSIX_SOURCE
   for the benefit of beef.c.  */
#if defined(ultrix) && defined(mips)
#include <machine/fpu.h>
#define swapRM(x) set_fpc_csr((get_fpc_csr(x) & ~3) | x)
#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

#if defined(m68k) || defined(mc68000)
/* This particular 68k dialect is m68k-hp-netBSD1.0A.
   Add -D_POSIX_SOURCE to the compilation options
   and change /bin/time to time in the makefile.  */
#define swapRM(x) fesetround(x)
#define Round_Down      2
#define Round_Near      0
#define Round_Up        3
#define Round_Zero      1
#define PC_24 1
#define PC_53 2
#define PC_64 0
#define Undef_Compilers
#define set_prec(x) fesetprec(x)
#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

#ifdef 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_TOWARDZERO
#define No_Prec
#endif

#if defined(i386) || defined(i86pc) || defined(i486) 
#ifndef Round_Near		/* For GCC especially */
#define Round_Near	0
#define Round_Down	1
#define Round_Up	2
#define Round_Zero	3
#define swapRM(x) 	fesetround(x)
#define PC_24   0
#define PC_53   2
#define PC_64   3
#define set_prec(x)	fesetprec(x)
#endif
#endif

#if defined(sparc) || defined(_sparc) || defined(__sparc) 
#ifndef Round_Near		/* For GCC especially */
#define Round_Near	0
#define Round_Down	3
#define Round_Up	2
#define Round_Zero	1
#define swapRM(x) 	fesetround(x)
#define No_Prec
#endif
#endif

#if !defined(No_Prec) && !defined(Cant_Prec) && !defined(Round_Near)

#define Round_Near	0
#define Round_Down	1
#define Round_Up	2
#define Round_Zero	3
#define swapRM(X) if ((X) != Round_Near) ucbfail( __FILE__ , __LINE__ ) ;
#define Cant_Prec

#endif

void
round_nearest()
{				/* set rounding direction to nearest */
#ifdef Round_Near	/* if rounding isn't defined, OK to do nothing */
	swapRM(Round_Near);
#endif
}

void
round_positive()
{				/* set rounding direction to +inf */
#ifdef Round_Up
	swapRM(Round_Up);
#else
	printf("Don't know how to round toward +infinity!\n");
	ucbfail( __FILE__, __LINE__ );
#endif
}

void
round_zero()
{				/* set rounding direction toward zero */
#ifndef Round_Zero
	printf("Don't know how to round toward zero!\n");
	ucbfail( __FILE__, __LINE__ );
#else
	swapRM(Round_Zero);
#endif
}

void generic_precision PROTO((void))
{
#ifdef No_Prec 		/* don't need to on RISCS */
	return;
#endif

#ifdef Cant_Prec	/* don't know how on CISCS */
#ifdef QP
	return;			/* assume extended is default */
#else
	printf("Don't know how to change rounding precision!\n");
	ucbfail( __FILE__, __LINE__ );
#endif
#endif

#if defined(SP) || defined(DP) || defined(QP)
#if !defined(No_Prec) && !defined(Cant_Prec)

#ifdef SP
#define Prec PC_24
#endif
#ifdef DP
#define Prec PC_53
#endif
#ifdef QP
#define Prec PC_64
#endif
	set_prec(Prec);

#endif
#endif
}

void default_precision PROTO((void))
{
#ifdef No_Prec 		/* don't need to on RISCS */
	return;
#endif

#ifdef Cant_Prec	/* don't know how on CISCS */
	return;			/* assume extended is default */
#endif

#if !defined(No_Prec) && !defined(Cant_Prec)
	set_prec(PC_64);
#endif
}

#ifdef ANSI_PROTOTYPES
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
}
