/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be externally linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss or reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#ifndef _MATH_H
#define	_MATH_H

/*
*	Definitions for the return value of the fpclassify() macro.
*/

enum {

	FP_NAN,							// Not a number
	FP_INFINITE,					// Infinite
	FP_ZERO,						// Zero
	FP_SUBNORMAL,					// Unnormalised number
	FP_NORMAL						// Normalised number
};

/*
*	Classification functions, selected by the macros below
*/

int _blm_fpclassd( double d )	__attribute__ ((const));
int _blm_fpclassf( float f )	__attribute__ ((const));
int _blm_isnand( double d )		__attribute__ ((const));
int _blm_isnanf( float f )		__attribute__ ((const));
int _blm_isinfd( double d )		__attribute__ ((const));
int _blm_isinff( float f )		__attribute__ ((const));
int _blm_iszerod( double d )	__attribute__ ((const));
int _blm_iszerof( float f )		__attribute__ ((const));
int _blm_isfind( double d )		__attribute__ ((const));
int _blm_isfinf( float d )		__attribute__ ((const));
int _blm_isnegd( double d )		__attribute__ ((const));
int _blm_isnegf( float d )		__attribute__ ((const));

/** @addtogroup ieee */
/** @{ */

/**
*	Classifies a real expression.
*
*	Returns the float point class of the expression. The \p FP_XXX classes
*	are anonymously defined as small integer values.
*
*	@param	x	A \p float or \p double expression.
*
*	@retval	FP_NAN			The expression is not a number
*	@retval	FP_INFINITE		The expression is infinite
*	@retval	FP_ZERO			The expression is zero
*	@retval	FP_SUBNORMAL	The expression is a denormalised number
*	@retval	FP_NORMAL		The expression is none of the above, it is a normal
*							real number within the full-precision representation
*							boundaries.
*/

#define	fpclassify(x)	\
				(sizeof(x)==sizeof(float)?_blm_fpclassf(x):_blm_fpclassd(x))

/**
*	Checks if a real expression is Not A Number.
*
*	The macro returns non-zero (actually 1) if its argument is a NaN, 0
*	otherwise. If the argument is not a \p float or \p double expression,
*	then the behaviour is unspecified.
*
*	@param	x	A \p float or \p double expression.
*
*	@return		A flag indicating whether the expression is NaN
*/

#define isnan(x)	(sizeof(x)==sizeof(float)?_blm_isnanf(x):_blm_isnand(x))

/**
*	Checks if a real expression is infinite.
*
*	The macro returns +1 if the expression's value is +infinity, -1 if the
*	expression's value is -infinity and 0 otherwise. If the argument is not
*	a \p float or \p double expression, then the behaviour is unspecified.
*
*	@param	x	A \p float or \p double expression.
*
*	@return		+1, 0 or -1 depending on whether x is (signed) infinite or not.
*/

#define isinf(x)	(sizeof(x)==sizeof(float)?_blm_isinff(x):_blm_isinfd(x))

/**
*	Checks if a real expression is a finite number.
*
*	The macro returns 1 if the expression's value is a finite number
*	and 0 otherwise. If the argument is not a \p float or \p double
*	expression, then the behaviour is unspecified.
*
*	@param	x	A \p float or \p double expression.
*
*	@return		1 if x is finite, 0 otherwise.
*/

#define isfinite(x)	(sizeof(x)==sizeof(float)?_blm_isfinf(x):_blm_isfind(x))

/**
*	Checks if a real expression is zero.
*
*	The macro returns +1 if the expression's value is +0, -1 if the
*	expression's value is -0 and 0 otherwise. If the argument is not
*	a \p float or \p double expression, then the behaviour is unspecified.
*
*	@param	x	A \p float or \p double expression.
*
*	@return		+1, 0 or -1 depending on whether x is (signed) zero or not.
*/

#define iszero(x)	(sizeof(x)==sizeof(float)?_blm_iszerof(x):_blm_iszerod(x))

/**
*	Checks if a real expression is negative.
*
*	The macro returns 1 if the signum bit of the expression is set,
*	0 otherwise. Note that the signum bit is undefined for NaNs. In any
*	other case the signum bit is valid. If the argument is not a \p float
*	or \p double expression, then the behaviour is unspecified.
*
*	@param	x	A \p float or \p double expression.
*
*	@return		1 if the expression is negative, 0 otherwise.
*/

#define signbit(x)	(sizeof(x)==sizeof(float)?_blm_isnegf(x):_blm_isnegd(x))

/**
*	Checks if a real expression is normalised.
*
*	The macro returns 1 if the argument is a normalised number,
*	0 otherwise. If the argument is not a \p float or \p double
*	expression, then the behaviour is unspecified.
*
*	@param	x	A \p float or \p double expression.
*
*	@return		1 if the expression is normalised, 0 otherwise.
*/

#define isnormal(x)	(fpclassify(x)==FP_NORMAL)

/** @} */

/*
*	Basic functions
*/

double	fabs( double )							__attribute__((const));
double	copysign( double, double )				__attribute__((const));
double	nan( const char * )						__attribute__((const));
double	infinity( void )						__attribute__((const));
double	floor( double )							__attribute__((const));
double	round( double x )						__attribute__((const));
double	trunc( double x )						__attribute__((const));
double	ceil( double x )						__attribute__((const));
double	ldexp( double x, int p )				__attribute__((const));
double	frexp( double x, int *p );
double	modf( double x, double *i );

float	fabsf( float )							__attribute__((const));
float	copysignf( float, float )				__attribute__((const));
float	nanf( const char * )					__attribute__((const));
float	infinityf( void )						__attribute__((const));
float	floorf( float )							__attribute__((const));
float	roundf( float )							__attribute__((const));
float	truncf( float )							__attribute__((const));
float	ceilf( float )							__attribute__((const));
float	ldexpf( float x, int p )				__attribute__((const));
float	frexpf( float x, int *p );
float	modff( float x, float *i );

/*
*	Transcendental functions
*/

double	sqrt( double x )						__attribute__((const));

double	sin( double x )							__attribute__((const));
double	cos( double x )							__attribute__((const));
double	tan( double x )							__attribute__((const));
double	cot( double x )							__attribute__((const));
double	asin( double x )						__attribute__((const));
double	acos( double x )						__attribute__((const));
double	atan( double x )						__attribute__((const));
double	atan2( double y, double x )				__attribute__((const));

double	exp( double x )							__attribute__((const));
double	exp2( double x )						__attribute__((const));
double	exp10( double x )						__attribute__((const));
double	log( double x )							__attribute__((const));
double	log2( double x )						__attribute__((const));
double	log10( double x )						__attribute__((const));

double	sinh( double x )						__attribute__((const));
double	cosh( double x )						__attribute__((const));
double	tanh( double x )						__attribute__((const));
double	asinh( double x )						__attribute__((const));
double	acosh( double x )						__attribute__((const));
double	atanh( double x )						__attribute__((const));

float	sqrtf( float x )						__attribute__((const));

float	sinf( float x )							__attribute__((const));
float	cosf( float x )							__attribute__((const));
float	tanf( float x )							__attribute__((const));
float	cotf( float x )							__attribute__((const));
float	asinf( float x )						__attribute__((const));
float	acosf( float x )						__attribute__((const));
float	atanf( float x )						__attribute__((const));
float	atan2f( float y, float x )				__attribute__((const));

float	expf( float x )							__attribute__((const));
float	exp2f( float x )						__attribute__((const));
float	exp10f( float x )						__attribute__((const));
float	logf( float x )							__attribute__((const));
float	log2f( float x )						__attribute__((const));
float	log10f( float x )						__attribute__((const));

float	sinhf( float x )						__attribute__((const));
float	coshf( float x )						__attribute__((const));
float	tanhf( float x )						__attribute__((const));
float	asinhf( float x )						__attribute__((const));
float	acoshf( float x )						__attribute__((const));
float	atanhf( float x )						__attribute__((const));

/*
*	Other float-point functions
*/

double	polynom( double x, const double *t, unsigned n ) __attribute__((pure));
float	polynomf( float x, const float *c, unsigned n )	 __attribute__((pure));

#endif

