#include "gpklib.h"
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <float.h>
#if LIBC_H_EXISTS
# include <libc.h>
#else
# include <stdlib.h>
#endif
#include "gpkNaN.h"
#include <math.h>

#include "gpkieee754.h"

# define FINITE	finite
# define ISNAN	isnan
# define FABS	fabs

#if 0

PLAIN_C int round(double x)
{
 int tmp = x>0 ? (int)(x+0.5) : -(int)(0.5-DBL_EPSILON-x);
 if(x-0.5>INT_MAX || x+0.5<INT_MIN)	{
	fflush(stdout);
	fprintf(stderr, "Round: domain error on %g\n", x);
	abort();
	return INT_NAN;
	}
 return tmp;
}
#endif

#ifdef __cplusplus


signed char roundC(float x)
{
 if(!FINITE(x))	{
	if(ISNAN(x))
		return SCHAR_NAN;
	return x>0 ? SCHAR_Max : SCHAR_Min;
	}

 const static float max = SCHAR_Max - (float)0.5;
 const static float min = SCHAR_Min + (float)0.5;
 signed char tmp;
 if(x >= max)
	tmp = SCHAR_Max;
 else if(x <= min)
	tmp = SCHAR_Min;
 else
 	tmp = x>0 ? (signed char)(x+(float)0.5) : -(signed char)((float)0.5-FLT_EPSILON-x);

 return tmp;
}


unsigned char roundU(float x)
{
 if(!FINITE(x))	{
	if(ISNAN(x))
		return UCHAR_NAN;
	return x>0 ? UCHAR_Max : UCHAR_Min;
	}

 const static float max = UCHAR_Max - (float)0.5;
 const static float min = UCHAR_Min + (float)0.5;
 unsigned char tmp;
 if(x >= max)
	tmp = UCHAR_Max;
 else if(x <= min)
	tmp = UCHAR_Min;
 else
 	tmp = (unsigned char)(x+(float)0.5);

 return tmp;
}




signed char roundC(double x)
{
 if(!finite(x))	{
	if(isnan(x))
		return SCHAR_NAN;
	return x>0 ? SCHAR_Max : SCHAR_Min;
	}

 const static double max = SCHAR_Max - 0.5;
 const static double min = SCHAR_Min + 0.5;
 signed char tmp;
 if(x >= max)
	tmp = SCHAR_Max;
 else if(x <= min)
	tmp = SCHAR_Min;
 else
 	tmp = x>0 ? (signed char)(x+0.5) : -(signed char)(0.5-DBL_EPSILON-x);

 return tmp;
}



unsigned char roundU(double x)
{
 if(!finite(x))	{
	if(isnan(x))
		return UCHAR_NAN;
	return x>0 ? UCHAR_Max : UCHAR_Min;
	}

 const static double max = UCHAR_Max - 0.5;
 const static double min = UCHAR_Min + 0.5;
 unsigned char tmp;
 if(x >= max)
	tmp = UCHAR_Max;
 else if(x <= min)
	tmp = UCHAR_Min;
 else
 	tmp = (unsigned char)(x+0.5);

 return tmp;
}





short roundS(float x)
{
 if(!FINITE(x))	{
	if(ISNAN(x))
		return SHRT_NAN;
	return x>0 ? SHRT_Max : SHRT_Min;
	}

 const static float max = SHRT_Max - 0.5;
 const static float min = SHRT_Min + 0.5;
 short tmp;
 if(x >= max)
	tmp = SHRT_Max;
 else if(x <= min)
	tmp = SHRT_Min;
 else
 	tmp = x>0 ? (int)(x+(float)0.5) : -(int)((float)0.5-FLT_EPSILON-x);

 return tmp;
}




long roundL(float x)
{
 if(!FINITE(x))	{
	if(ISNAN(x))
		return LONG_NAN;
	return x>0 ? LONG_Max : LONG_Min;
	}

 long tmp;
 if(x+(float)0.5 >= LONG_Max)
	tmp = LONG_Max;
 if(x-(float)0.5 <= LONG_Min)
	tmp = LONG_Min;
 else
	tmp = x>0 ? (long)(x+(float)0.5) : -(long)((float)0.5-FLT_EPSILON-x);

 return tmp;
}




int roundI(float x)
{
 if(!FINITE(x))	{
	if(ISNAN(x))
		return INT_NAN;
	return x>0 ? INT_Max : INT_Min;
	}

 int tmp;
 if(x+(float)0.5 >= INT_Max)
	tmp = INT_Max;
 if(x-(float)0.5 <= INT_Min)
	tmp = INT_Min;
 else
	tmp = x>0 ? (int)(x+(float)0.5) : -(int)((float)0.5-FLT_EPSILON-x);

 return tmp;
}




short roundS(double x)
{
 if(!finite(x))	{
	if(isnan(x))
		return SHRT_NAN;
	return x>0 ? SHRT_Max : SHRT_Min;
	}

 const static double max = SHRT_Max - 0.5;
 const static double min = SHRT_Min + 0.5;
 short tmp;
 if(x >= max)
	tmp = SHRT_Max;
 else if(x <= min)
	tmp = SHRT_Min;
 else
 	tmp = x>0 ? (int)(x+(double)0.5) : -(int)((double)0.5-DBL_EPSILON-x);

 return tmp;
}




long roundL(double x)
{
 if(!finite(x))	{
	if(isnan(x))
		return LONG_NAN;
	return x>0 ? LONG_Max : LONG_Min;
	}

 long tmp;
 if(x+(double)0.5 >= LONG_Max)
	tmp = LONG_Max;
 if(x-(double)0.5 <= LONG_Min)
	tmp = LONG_Min;
 else
	tmp = x>0 ? (long)(x+(double)0.5) : -(long)((double)0.5-DBL_EPSILON-x);

 return tmp;
}




int roundI(double x)
{
 if(!finite(x))	{
	if(isnan(x))
		return INT_NAN;
	return x>0 ? INT_Max : INT_Min;
	}

 int tmp;
 if(x+(double)0.5 >= INT_Max)
	tmp = INT_Max;
 if(x-(double)0.5 <= INT_Min)
	tmp = INT_Min;
 else
	tmp = x>0 ? (int)(x+(double)0.5) : -(int)((double)0.5-DBL_EPSILON-x);

 return tmp;
}

#endif
