/*****************************************************************************
 * $Id: math.cc,v 1.1 2006/10/21 00:19:08 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Math test.
 *//*
 * LEGAL:	COPYRIGHT (C) 2006 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#define TESTING 1
#include "test.hh"
#include "gfx_types.hh"
#include "gfx_math.hh"
#include "gfx_funcs.hh"
#include "gfx_funcs2.hh"

/*****************************************************************************
 * This asm code in C++ template returning args by reference looks suspicious,
 * so it's tested with different float types.
 *****************************************************************************/
template<typename FP>
void
SinCos_( Radian rad, FP& si, FP& co )
{
	asm("fsincos" : "=t" (co), "=u" (si) : "0" (rad));
}
bool
CheckSinCos( fp rad )
{
#if CPU_X86
	errno = 0;
 {
	fp si, co;
	SinCos_( rad, si, co );
	fp si2, co2;
	si2 = sin( rad );
	co2 = cos( rad );
	if ( FNE(si,si2) ) return false;
	if ( FNE(co,co2) ) return false;
 }

 {
	fpx si, co;
	SinCos_( rad, si, co );
	fpx si2, co2;
	si2 = sin( rad );
	co2 = cos( rad );
	if ( FNE(si,si2) ) return false;
	if ( FNE(co,co2) ) return false;
 }

 {
	long double si, co;
	SinCos_( rad, si, co );
	long double si2, co2;
	si2 = sin( rad );
	co2 = cos( rad );
	if ( FNE(si,si2) ) return false;
	if ( FNE(co,co2) ) return false;
 }

	return errno == 0;
#else
	return true;
#endif
}

/*****************************************************************************
 * Test SinCos().
 *****************************************************************************/
bool
TestSinCos( void )
{
	cerr << "============================================\n";
	cerr << "Testing SinCos() inline assembly. \n";
	cerr << "============================================\n";

	if ( ! CheckSinCos( 0.0 ) ) goto Error;
	if ( ! CheckSinCos( 1.0 ) ) goto Error;
	if ( ! CheckSinCos( -1.0 ) ) goto Error;
	if ( ! CheckSinCos( -0.5 ) ) goto Error;
	if ( ! CheckSinCos( gfx::PI ) ) goto Error;
	if ( ! CheckSinCos( gfx::PI2 ) ) goto Error;
	if ( ! CheckSinCos( -gfx::PI ) ) goto Error;
	if ( ! CheckSinCos( -gfx::PI2 ) ) goto Error;
	if ( ! CheckSinCos( gfx::PI * 2.0 ) ) goto Error;
	if ( ! CheckSinCos( gfx::PI2 * 2.0 ) ) goto Error;

	return true;

Error:
	return false;
}

/*****************************************************************************
 * Test FEQ( const FP a, const FP b, const uint fracDigits )
 *****************************************************************************/
bool
TestFEQ( void )
{
	cerr << "============================================\n";
	cerr << "Testing FEQ(f,f,fracDigits). \n";
	cerr << "============================================\n";

 {
    float a = 1.2345;
    float b = 1.2345;
    if ( ! FEQ(a,b,4) ) return false;
    if ( ! FEQ(a,b,0) ) return false;
    if ( ! FEQ(a,b,1) ) return false;
    if ( ! FEQ(a,b,6) ) return false;
 }

 {
    double a = 1.2345;
    double b = 1.2345;
    if ( ! FEQ(a,b,4) ) return false;
    if ( ! FEQ(a,b,0) ) return false;
    if ( ! FEQ(a,b,1) ) return false;
    if ( ! FEQ(a,b,6) ) return false;
 }

 {
    float a = 1.22;
    float b = 1.24;
    if ( ! FEQ(a,b,0) ) return false;
    if ( ! FEQ(a,b,1) ) return false;
    if (   FEQ(a,b,2) ) return false;
 }

 {
    float a = 1.22;
    float b = 2.22;
    if ( FEQ(a,b,0) ) return false;
    if ( FEQ(a,b,1) ) return false;
    if ( FEQ(a,b,2) ) return false;
 }

 {
    float a = -3.21;
    float b =  3.21;
    if ( FEQ(a,b,0) ) return false;
    if ( FEQ(a,b,1) ) return false;
    if ( FEQ(a,b,2) ) return false;
 }

    return true;
}

/*****************************************************************************
 * main.
 *****************************************************************************/
int main( int argc, char** argv )
{
	GFX_INIT( argv[0] );
	int res = 1;
	if ( TestSinCos()
      && TestFEQ()
       )
	{
		cerr << "Test PASSED.\n";
		res = 0;
	}
	else
	{
		cerr << "Test FAILED! \n";
		res = 1;
	}
	GFX_CLEANUP();
	exit( res );
}
