//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * 数学のテスト実装
 * @author Junpee
 */

#include "Test/stdafx.h"
#include "Core/System/MathTest.h"
#include <Core/System/Math.h>
#include <Core/Utility/Timer.h>
#include <cmath>// sqrt(-1)に使用

// 大きなfloat値
float MathTest::bigFloat_ = 3.402823466e+38f;

//------------------------------------------------------------------------------
// テストスィートの取得
Test* MathTest::suite(){
	TestSuite* suite = new TestSuite("MathTest");
	suite->addTest(new TestCaller(MathTest, testFixedNumber));
	suite->addTest(new TestCaller(MathTest, testUnitChange));
	suite->addTest(new TestCaller(MathTest, testMaxMin));
	suite->addTest(new TestCaller(MathTest, testAbs));
	suite->addTest(new TestCaller(MathTest, testFloorCeil));
	suite->addTest(new TestCaller(MathTest, testFloat));
	suite->addTest(new TestCaller(MathTest, testExpLog));
	suite->addTest(new TestCaller(MathTest, testTrigonometricFunction));
	return suite;
}
//------------------------------------------------------------------------------
// 定数テスト
void MathTest::testFixedNumber(){
	TestEquals((float)3.14159265358979323846, Math::PI);
	TestEquals((float)(3.14159265358979323846 * 4.), Math::quadruplePI);
	TestEquals((float)(3.14159265358979323846 * 2.), Math::doublePI);
	TestEquals((float)(3.14159265358979323846 / 2.), Math::halfPI);
	TestEquals((float)(3.14159265358979323846 / 4.), Math::quadrantPI);
	TestEquals(1e-06f, Math::epsilon);
}
//------------------------------------------------------------------------------
// 単位変換テスト
void MathTest::testUnitChange(){
	TestEquals(180.f, Math::toDegree(Math::PI));
	TestEpsilonEquals(Math::PI, Math::toRadian(180.f), Math::epsilon);
}
//------------------------------------------------------------------------------
// 最大最小テスト
void MathTest::testMaxMin(){
	TestEquals(1, Math::maximum(1, -1));
	TestEquals(1, Math::maximum(-1, 1));
	TestEquals(-1, Math::minimum(1, -1));
	TestEquals(-1, Math::minimum(-1, 1));
	TestEquals(1.f, Math::maximum(1.f, -1.f));
	TestEquals(1.f, Math::maximum(-1.f, 1.f));
	TestEquals(-1.f, Math::minimum(1.f, -1.f));
	TestEquals(-1.f, Math::minimum(-1.f, 1.f));
}
//------------------------------------------------------------------------------
// 絶対値テスト
void MathTest::testAbs(){
	TestEquals(0, Math::abs(0));
	TestEquals(1, Math::abs(-1));
	TestEquals(-0.f, Math::abs(0.f));
	TestEquals(1.f, Math::abs(-1.f));
}
//------------------------------------------------------------------------------
// 切り捨て切り上げテスト
void MathTest::testFloorCeil(){
	float value = 1.2345f;
	TestEquals(1.f, Math::floor(value));
	TestEquals(2.f, Math::ceil(value));
	value = -1.2345f;
	TestEquals(-2.f, Math::floor(value));
	TestEquals(-1.f, Math::ceil(value));
	value = 12345.01f;
	TestEquals(12345.f, Math::floor(value));
	TestEquals(12346.f, Math::ceil(value));
}
//------------------------------------------------------------------------------
// 浮動小数値演算テスト
void MathTest::testFloat(){
	// あまり
	TestEquals(0.25f, Math::fmod(5.25f, 2.5f));
	float integer;
	TestEquals(0.25f, Math::modf(1.25f, &integer));
	TestEquals(1.f, integer);
	// 平方根
	TestEquals(10.f, Math::sqrt(100.f));
	// クラスチェック
	TestAssert(Math::classCheck(2.f / 3.f));
#ifdef _DEBUG // リリースでは上手く再現できず
	TestAssert(!Math::classCheck(bigFloat_ * 2));
	TestAssert(!Math::classCheck(bigFloat_ * -2));
#endif
	TestAssert(!Math::classCheck(::sqrtf(-1.f)));
}
//------------------------------------------------------------------------------
// 指数、対数テスト
void MathTest::testExpLog(){
	TestEquals(256.f, Math::pow(2.f, 8.f));
	TestEquals(10.f, exp(2.302585093f));
	TestEquals(9.1049795f, log(9000.f));
	TestEquals(3.9542425f, log10(9000.f));
	TestAssert(Math::checkPow2(256));
	TestAssert(!Math::checkPow2(255));
}
//------------------------------------------------------------------------------
// 三角関数テスト
void MathTest::testTrigonometricFunction(){
	// 通常
	TestEquals(1.f, Math::sin(Math::halfPI));
	TestEquals(-1.f, Math::cos(Math::PI));
	TestEquals(1.f, Math::tan(Math::quadrantPI));
	// 双曲
	TestEquals(2.301299f, Math::sinh(Math::halfPI));
	TestEquals(2.5091786f, Math::cosh(Math::halfPI));
	TestEquals(0.7615942f, Math::tanh(1.f));
	// 逆
	TestEquals(0.f, Math::asin(0.f));
	TestEquals(Math::halfPI, Math::acos(0.f));
	TestEquals(0.4636476f, Math::atan(0.5f));
	TestEquals(0.09966865f, Math::atan2(0.5f, 5.f));
	TestEquals(Math::quadrantPI + Math::halfPI,
		Math::atan2(Math::sin(Math::quadrantPI + Math::halfPI),
		Math::cos(Math::quadrantPI + Math::halfPI)));
}
//------------------------------------------------------------------------------
