/* Public domain */ /* * This program tests the Agar math library (ag_math). */ #include "agartest.h" #include #include #include #include #include #include #include #include #include #include #include #include "config/have_rand48.h" #include #include #define NREALS 10000 #define NVECTORS 1000 #define NMATRICES 100 typedef struct { AG_TestInstance _inherit; M_Real r[NREALS]; M_Vector2 v2[NVECTORS]; M_Vector3 v3[NVECTORS]; M_Vector4 v4[NVECTORS]; M_Matrix44 m44[NMATRICES]; int curReal, curVec, curMat; } MyTestInstance; M_Real realJunk = 0.0; static __inline__ M_Real RandomReal(MyTestInstance *ti) { if (ti->curReal+1 >= NREALS) { ti->curReal = 0; } return (ti->r[ti->curReal++]); } static __inline__ M_Vector3 RandomVector3(MyTestInstance *ti) { if (ti->curVec+1 >= NVECTORS) { ti->curVec = 0; } return (ti->v3[ti->curVec++]); } static __inline__ M_Vector4 RandomVector4(MyTestInstance *ti) { if (ti->curVec+1 >= NVECTORS) { ti->curVec = 0; } return (ti->v4[ti->curVec++]); } static __inline__ M_Matrix44 RandomMatrix44(MyTestInstance *ti) { if (ti->curMat+1 >= NMATRICES) { ti->curMat = 0; } return (ti->m44[ti->curMat++]); } #include "math_vector3.h" #include "math_matrix44.h" static int Init(void *obj) { MyTestInstance *ti = obj; int i, j; M_InitSubsystem(); ti->curReal = 0; ti->curVec = 0; ti->curMat = 0; for (i = 0; i < NREALS ; i++) { #ifdef HAVE_RAND48 ti->r[i] = (M_Real)drand48(); #else ti->r[i] = (M_Real)i; #endif } for (i = 0; i < NVECTORS; i++) { #ifdef HAVE_RAND48 ti->v2[i] = M_VECTOR2((M_Real)drand48(), (M_Real)drand48()); # ifdef HAVE_SSE ti->v3[i] = M_VECTOR3((float)drand48(), (float)drand48(), (float)drand48()); ti->v4[i] = M_VECTOR4((float)drand48(), (float)drand48(), (float)drand48(), (float)drand48()); # else ti->v3[i] = M_VECTOR3((M_Real)drand48(), (M_Real)drand48(), (M_Real)drand48()); ti->v4[i] = M_VECTOR4((M_Real)drand48(), (M_Real)drand48(), (M_Real)drand48(), (M_Real)drand48()); # endif #else ti->v2[i] = M_VECTOR2((M_Real)(i+1), (M_Real)(i*i)); # ifdef HAVE_SSE ti->v3[i] = M_VECTOR3((float)(i+1), (float)(i*i), (float)(i*i*i)); ti->v4[i] = M_VECTOR4((float)(i+1), (float)(i*i), (float)(i*i*i), (float)(i*i*i)); # else ti->v3[i] = M_VECTOR3((M_Real)(i+1), (M_Real)(i*i), (M_Real)(i*i*i)); ti->v4[i] = M_VECTOR4((M_Real)(i+1), (M_Real)(i*i), (M_Real)(i*i*i), (M_Real)(i*i*i)); # endif #endif } for (i = 0; i < NMATRICES; i++) { double rands[16]; #ifdef HAVE_RAND48 for (j = 0; j < 16; j++) rands[j] = drand48(); #else for (j = 0; j < 16; j++) rands[j] = (double)(i*j + i + i*i + i*i*j + 1); #endif M_MatFromDoubles44(&ti->m44[i], rands); } return (0); } static void TestComplex(AG_TestInstance *ti) { M_Complex C1, C2, C1mi, C1plusC2, C1multC2; M_Real C1mod, C1arg; C1.r = 1.0; C1.i = 1.1; C2.r = 10.0; C2.i = 2.2; C1mi = M_ComplexMultiplicativeInverse(C1); C1mod = M_ComplexModulus(C1); C1arg = M_ComplexArg(C1); C1plusC2 = M_ComplexAdd(C1, C2); C1multC2 = M_ComplexMult(C1, C2); TestMsgS(ti, AG_Printf("\tC1=%[C], C2=%[C]", &C1, &C2)); TestMsgS(ti, AG_Printf("\tC1 mult. inverse = %[C]", &C1mi)); TestMsgS(ti, AG_Printf("\tC1 modulus = %[R]", &C1mod)); TestMsgS(ti, AG_Printf("\tC1 argument = %[R]", &C1arg)); TestMsgS(ti, AG_Printf("\tC1+C2 = %[C]", &C1plusC2)); TestMsgS(ti, AG_Printf("\tC1*C2 = %[C]", &C1multC2)); } static void TestVector(AG_TestInstance *ti) { M_Vector *a, *b, *AplusB, *AsubB, *aNorm, *bNorm, *aLERP, *aPow2, *a2, *b2; M_Real aLen, bLen, abDist, AdotB; M_Real someReal = 1.234567, someReal2 = 2.345; a = M_VecNew(4); a->v[0] = 1.1; a->v[1] = 2.2; a->v[2] = 3.3; a->v[3] = 4.4; b = M_VecNew(4); b->v[0] = 10.0; b->v[1] = 20.0; b->v[2] = 30.0; b->v[3] = 40.0; aLen = M_VecLen(a); bLen = M_VecLen(b); a2 = M_VecScale(a, 2.0); b2 = M_VecScale(b, 2.0); AplusB = M_VecAdd(a, b); AsubB = M_VecSub(a, b); aNorm = M_VecNorm(a); bNorm = M_VecNorm(b); aLERP = M_VecLERP(a, b, 0.5); aPow2 = M_VecElemPow(a, 2.0); abDist = M_VecDistance(a, b); AdotB = M_VecDot(a, b); TestMsgS(ti, AG_Printf("\tReal=%[R], Real2=%[R]", &someReal, &someReal2)); TestMsgS(ti, AG_Printf("\ta=%[V], b=%[V]", a, b)); TestMsgS(ti, AG_Printf("\t2a=%[V], 2b=%[V]", a2, b2)); TestMsgS(ti, AG_Printf("\tlen(a)=%[R], len(b)=%[R]", &aLen, &bLen)); TestMsgS(ti, AG_Printf("\tnorm(a)=%[V], norm(b)=%[V]", aNorm, bNorm)); TestMsgS(ti, AG_Printf("\ta+b=%[V], a-b=%[V]", AplusB, AsubB)); TestMsgS(ti, AG_Printf("\ta dot b=%[R]", &AdotB)); TestMsgS(ti, AG_Printf("\tdist(a,b)=%[R]", &abDist)); TestMsgS(ti, AG_Printf("\tlerp(a,b,1/2)=%[V]", aLERP)); TestMsgS(ti, AG_Printf("\tpow2(a)=%[V]", aPow2)); M_VecFree(a); M_VecFree(b); M_VecFree(a2); M_VecFree(b2); M_VecFree(AplusB); M_VecFree(AsubB); M_VecFree(aNorm); M_VecFree(bNorm); M_VecFree(aLERP); M_VecFree(aPow2); } static void TestVector3(AG_TestInstance *ti) { M_Vector3 a = M_VECTOR3(1.1, 2.8, 3.7); M_Vector3 b = M_VECTOR3(15.1, 52.8, 35.0); M_Real aLen = M_VecLen3(a), bLen = M_VecLen3(b); M_Vector3 Anorm = M_VecNorm3(a), Bnorm = M_VecNorm3(b); M_Real AdotB = M_VecDot3(a, b); M_Vector3 AcrossB = M_VecCross3(a, b); M_Vector3 AnormcrossB = M_VecNormCross3(a, b); M_Real AdistB = M_VecDistance3(a, b); M_Vector3 AavgB = M_VecAvg3(a, b); TestMsgS(ti, AG_Printf("\ta=%[V3], b=%[V3]", &a, &b)); TestMsgS(ti, AG_Printf("\tlen(a)=%[R], len(b)=%[R]", &aLen, &bLen)); TestMsgS(ti, AG_Printf("\tnorm(a)=%[V3], norm(b)=%[V3]", &Anorm, &Bnorm)); TestMsgS(ti, AG_Printf("\ta dot b=%[R]", &AdotB)); TestMsgS(ti, AG_Printf("\ta x b=%[V3]", &AcrossB)); TestMsgS(ti, AG_Printf("\tnorm(a x b)=%[V3]", &AnormcrossB)); TestMsgS(ti, AG_Printf("\tdist(a,b)=%[R]", &AdistB)); TestMsgS(ti, AG_Printf("\tavg(a,b)=%[V3]", &AavgB)); } static void TestMatrix(AG_TestInstance *ti) { M_Matrix *M; M = M_New(5,5); M_SetIdentity(M); TestMsgS(ti, AG_Printf("\tM=%[M]", M)); M_Free(M); } static void TestMatrix44(AG_TestInstance *ti) { M_Matrix44 A, B, AB, ABinv, ABt, Rot, UniScale; M_MatIdentity44v(&A); M_MatIdentity44v(&B); A.m[0][1] = 2.0; A.m[1][0] = 3.0; A.m[0][2] = 4.0; A.m[2][0] = 5.0; A.m[0][3] = 6.0; A.m[3][0] = 7.0; B.m[1][1] = 10.0; B.m[1][2] = 0.1; B.m[2][1] = 0.2; AB = M_MatMult44(B, A); ABinv = M_MatInvert44(AB); ABt = M_MatTranspose44(AB); Rot = M_MatIdentity44(); UniScale = M_MatIdentity44(); M_MatRotateAxis44(&Rot, M_Radians(33.0), M_VecNorm3(M_VECTOR3(11.6, 4.51, 8.5))); M_MatUniScale44(&UniScale, 6.66); TestMsgS(ti, AG_Printf("\tA=%[M44]", &A)); TestMsgS(ti, AG_Printf("\tB=%[M44]", &B)); TestMsgS(ti, AG_Printf("\tAB=%[M44]", &AB)); TestMsgS(ti, AG_Printf("\tinv(AB)=%[M44]", &ABinv)); TestMsgS(ti, AG_Printf("\ttranspose(AB)= %[M44]", &ABt)); TestMsgS(ti, AG_Printf("\tRot=%[M44]", &Rot)); TestMsgS(ti, AG_Printf("\tUniScale=%[M44]", &UniScale)); } static int Test(void *obj) { AG_TestInstance *ti = obj; const M_VectorOps3 *prevVecOps3 = mVecOps3; const M_MatrixOps44 *prevMatOps44 = mMatOps44; TestMsg(ti, "Agar-Math settings:"); /* Standard Precision */ #if defined(QUAD_PRECISION) TestMsg(ti, "\tPrecision: Quad"); #elif defined(DOUBLE_PRECISION) TestMsg(ti, "\tPrecision: Double"); #elif defined(SINGLE_PRECISION) TestMsg(ti, "\tPrecision: Single"); #endif /* AltiVec support */ #if defined(HAVE_ALTIVEC) TestMsg(ti, "\tAltiVec support is available"); # if defined(INLINE_ALTIVEC) TestMsg(ti, "\tAltiVec extensions are compiled INLINE"); # endif #endif /* SSE support */ #if defined(HAVE_SSE3) TestMsg(ti, "\tSSE3 extensions are available"); #elif defined(HAVE_SSE2) TestMsg(ti, "\tSSE2 extensions are available"); #elif defined(HAVE_SSE) TestMsg(ti, "\tSSE extensions are available"); #endif #if defined(INLINE_SSE) TestMsg(ti, "\tSSE extensions are compiled INLINE"); #endif TestMsg(ti, "\tM_Vector engine: %s", mVecOps->name); TestMsg(ti, "\tM_Vector2 engine: %s", mVecOps2->name); TestMsg(ti, "\tM_Vector3 engine: %s", mVecOps3->name); TestMsg(ti, "\tM_Vector4 engine: %s", mVecOps4->name); TestMsg(ti, "\tM_Matrix engine: %s", mMatOps->name); TestMsg(ti, "\tM_Matrix44 engine: %s", mMatOps44->name); TestMsgS(ti, ""); mVecOps3 = &mVecOps3_FPU; mMatOps44 = &mMatOps44_FPU; TestMsg(ti, "M_Complex Test (FPU):"); TestComplex(ti); TestMsg(ti, "M_Vector Test (FPU):"); TestVector(ti); TestMsg(ti, "M_Matrix Test (FPU):"); TestMatrix(ti); TestMsg(ti, "M_Vector3 Test (FPU):"); TestVector3(ti); TestMsg(ti, "M_Matrix44 Test (FPU):"); TestMatrix44(ti); #if defined(HAVE_SSE) mVecOps3 = &mVecOps3_SSE; mMatOps44 = &mMatOps44_SSE; TestMsgS(ti, ""); TestMsgS(ti, "M_Complex Test (SSE):"); TestComplex(ti); TestMsgS(ti, "M_Vector Test (SSE):"); TestVector(ti); TestMsgS(ti, "M_Matrix Test (SSE):"); TestMatrix(ti); TestMsgS(ti, "M_Vector3 Test (SSE):"); TestVector3(ti); TestMsgS(ti, "M_Matrix44 Test (SSE):"); TestMatrix44(ti); #endif /* HAVE_SSE */ mMatOps44 = prevMatOps44; mVecOps3 = prevVecOps3; return (0); } static int Bench(void *obj) { AG_TestInstance *ti = obj; const M_VectorOps3 *prevVecOps3 = mVecOps3; const M_MatrixOps44 *prevMatOps44 = mMatOps44; TestMsg(ti, ""); TestMsg(ti, AGSI_LEAGUE_SPARTAN "A G A R - M A T H M I C R O B E N C H M A R K S"); #if defined(INLINE_SSE) TestMsg(ti, "M_Vector3 Microbenchmark (INLINE SSE):"); TestExecBenchmark(obj, &mathBenchVector3); #else /* !INLINE_SSE */ mVecOps3 = &mVecOps3_FPU; mMatOps44 = &mMatOps44_FPU; TestMsg(ti, "M_Vector3 Microbenchmark (FPU):"); TestExecBenchmark(obj, &mathBenchVector3); TestMsg(ti, "M_Matrix44 Microbenchmark (FPU):"); TestExecBenchmark(obj, &mathBenchMatrix44); # ifdef HAVE_SSE mVecOps3 = &mVecOps3_SSE; mMatOps44 = &mMatOps44_SSE; TestMsg(ti, "M_Vector3 Microbenchmark (SSE):"); TestExecBenchmark(obj, &mathBenchVector3); TestMsg(ti, "M_Matrix44 Microbenchmark (SSE):"); TestExecBenchmark(obj, &mathBenchMatrix44); # endif #endif /* !INLINE_SSE */ mMatOps44 = prevMatOps44; mVecOps3 = prevVecOps3; return (0); } const AG_TestCase mathTest = { AGSI_IDEOGRAM AGSI_MATH_X_EQUALS AGSI_RST, "math", N_("Test Agar's math library. Run multiple times to create threads." AGSI_IDEOGRAM AGSI_THREADS AGSI_RST), "1.7.0", 0, sizeof(MyTestInstance), Init, NULL, /* destroy */ Test, NULL, /* testGUI */ Bench };