* Remove "lame-ass" Signed-off-by: Simran Brucherseifer <simran.brucherseifer@gmail.com> * Substitute "dumb" with "basic" Signed-off-by: Simran Brucherseifer <simran.brucherseifer@gmail.com> * Substitute "whitelist" with "approved list" Signed-off-by: Simran Brucherseifer <simran.brucherseifer@gmail.com> * Substitute "sanity check" with "validation" or "validate" Also rename "sane" to "valid" and "insane" to "invalid" Signed-off-by: Simran Brucherseifer <simran.brucherseifer@gmail.com> * Rename enum values to VALIDATION_PASSED and VALIDATION_FAILED Signed-off-by: Simran Brucherseifer <simran.brucherseifer@gmail.com> * Rename methods to validate[Shared]View() Signed-off-by: Simran Brucherseifer <simran.brucherseifer@gmail.com> * Mention renamed validate[Shared]View() methods in changlog Signed-off-by: Simran Brucherseifer <simran.brucherseifer@gmail.com> * Actually just list the user-visible change Signed-off-by: Simran Brucherseifer <simran.brucherseifer@gmail.com> Co-authored-by: Patrick Hodoul <patrickhodoul@gmail.com> Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
882 lines
35 KiB
C++
882 lines
35 KiB
C++
// SPDX-License-Identifier: BSD-3-Clause
|
|
// Copyright Contributors to the OpenColorIO Project.
|
|
|
|
|
|
#include <limits>
|
|
|
|
#include "MathUtils.cpp"
|
|
|
|
#include "testutils/UnitTest.h"
|
|
|
|
namespace OCIO = OCIO_NAMESPACE;
|
|
|
|
|
|
namespace
|
|
{
|
|
void GetMxbResult(float* vout, float* m, float* x, float* v)
|
|
{
|
|
OCIO::GetM44V4Product(vout, m, x);
|
|
OCIO::GetV4Sum(vout, vout, v);
|
|
}
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, is_scalar_equal_to_zero)
|
|
{
|
|
OCIO_CHECK_EQUAL(OCIO::IsScalarEqualToZero(0.0f), true);
|
|
OCIO_CHECK_EQUAL(OCIO::IsScalarEqualToZero(-0.0f), true);
|
|
|
|
OCIO_CHECK_EQUAL(OCIO::IsScalarEqualToZero(-1.072883670794056e-09f), false);
|
|
OCIO_CHECK_EQUAL(OCIO::IsScalarEqualToZero(1.072883670794056e-09f), false);
|
|
|
|
OCIO_CHECK_EQUAL(OCIO::IsScalarEqualToZero(-1.072883670794056e-03f), false);
|
|
OCIO_CHECK_EQUAL(OCIO::IsScalarEqualToZero(1.072883670794056e-03f), false);
|
|
|
|
OCIO_CHECK_EQUAL(OCIO::IsScalarEqualToZero(-1.072883670794056e-01f), false);
|
|
OCIO_CHECK_EQUAL(OCIO::IsScalarEqualToZero(1.072883670794056e-01f), false);
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, get_m44_inverse)
|
|
{
|
|
// This is a degenerate matrix, and shouldn't be invertible.
|
|
float m[] = { 0.3f, 0.3f, 0.3f, 0.0f,
|
|
0.3f, 0.3f, 0.3f, 0.0f,
|
|
0.3f, 0.3f, 0.3f, 0.0f,
|
|
0.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
float mout[16];
|
|
bool invertsuccess = OCIO::GetM44Inverse(mout, m);
|
|
OCIO_CHECK_EQUAL(invertsuccess, false);
|
|
}
|
|
|
|
|
|
OCIO_ADD_TEST(MathUtils, m44_m44_product)
|
|
{
|
|
float mout[16];
|
|
float m1[] = { 1.0f, 2.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 1.0f, 0.0f,
|
|
1.0f, 0.0f, 1.0f, 0.0f,
|
|
0.0f, 1.0f, 3.0f, 1.0f };
|
|
float m2[] = { 1.0f, 1.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 0.0f, 0.0f,
|
|
0.0f, 0.0f, 1.0f, 0.0f,
|
|
2.0f, 0.0f, 0.0f, 1.0f };
|
|
OCIO::GetM44M44Product(mout, m1, m2);
|
|
|
|
float mcorrect[] = { 1.0f, 3.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 1.0f, 0.0f,
|
|
1.0f, 1.0f, 1.0f, 0.0f,
|
|
2.0f, 1.0f, 3.0f, 1.0f };
|
|
|
|
for(int i=0; i<16; ++i)
|
|
{
|
|
OCIO_CHECK_EQUAL(mout[i], mcorrect[i]);
|
|
}
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, m44_v4_product)
|
|
{
|
|
float vout[4];
|
|
float m[] = { 1.0f, 2.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 1.0f, 0.0f,
|
|
1.0f, 0.0f, 1.0f, 0.0f,
|
|
0.0f, 1.0f, 3.0f, 1.0f };
|
|
float v[] = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
OCIO::GetM44V4Product(vout, m, v);
|
|
|
|
float vcorrect[] = { 5.0f, 5.0f, 4.0f, 15.0f };
|
|
|
|
for(int i=0; i<4; ++i)
|
|
{
|
|
OCIO_CHECK_EQUAL(vout[i], vcorrect[i]);
|
|
}
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, v4_add)
|
|
{
|
|
float vout[4];
|
|
float v1[] = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
float v2[] = { 3.0f, 1.0f, 4.0f, 1.0f };
|
|
OCIO::GetV4Sum(vout, v1, v2);
|
|
|
|
float vcorrect[] = { 4.0f, 3.0f, 7.0f, 5.0f };
|
|
|
|
for(int i=0; i<4; ++i)
|
|
{
|
|
OCIO_CHECK_EQUAL(vout[i], vcorrect[i]);
|
|
}
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, mxb_eval)
|
|
{
|
|
float vout[4];
|
|
float m[] = { 1.0f, 2.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 1.0f, 0.0f,
|
|
1.0f, 0.0f, 1.0f, 0.0f,
|
|
0.0f, 1.0f, 3.0f, 1.0f };
|
|
float x[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
float v[] = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
GetMxbResult(vout, m, x, v);
|
|
|
|
float vcorrect[] = { 4.0f, 4.0f, 5.0f, 9.0f };
|
|
|
|
for(int i=0; i<4; ++i)
|
|
{
|
|
OCIO_CHECK_EQUAL(vout[i], vcorrect[i]);
|
|
}
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, combine_two_mxb)
|
|
{
|
|
float m1[] = { 1.0f, 0.0f, 2.0f, 0.0f,
|
|
2.0f, 1.0f, 0.0f, 1.0f,
|
|
0.0f, 1.0f, 2.0f, 0.0f,
|
|
1.0f, 0.0f, 0.0f, 1.0f };
|
|
float v1[] = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
float m2[] = { 2.0f, 1.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 0.0f, 0.0f,
|
|
1.0f, 0.0f, 3.0f, 0.0f,
|
|
1.0f,1.0f, 1.0f, 1.0f };
|
|
float v2[] = { 0.0f, 2.0f, 1.0f, 0.0f };
|
|
float tolerance = 1e-9f;
|
|
|
|
{
|
|
float x[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
float vout[4];
|
|
|
|
// Combine two mx+b operations, and apply to test point
|
|
float mout[16];
|
|
float vcombined[4];
|
|
OCIO::GetMxbCombine(mout, vout, m1, v1, m2, v2);
|
|
GetMxbResult(vcombined, mout, x, vout);
|
|
|
|
// Sequentially apply the two mx+b operations.
|
|
GetMxbResult(vout, m1, x, v1);
|
|
GetMxbResult(vout, m2, vout, v2);
|
|
|
|
// Compare outputs
|
|
for(int i=0; i<4; ++i)
|
|
{
|
|
OCIO_CHECK_CLOSE(vcombined[i], vout[i], tolerance);
|
|
}
|
|
}
|
|
|
|
{
|
|
float x[] = { 6.0f, 0.5f, -2.0f, -0.1f };
|
|
float vout[4];
|
|
|
|
float mout[16];
|
|
float vcombined[4];
|
|
OCIO::GetMxbCombine(mout, vout, m1, v1, m2, v2);
|
|
GetMxbResult(vcombined, mout, x, vout);
|
|
|
|
GetMxbResult(vout, m1, x, v1);
|
|
GetMxbResult(vout, m2, vout, v2);
|
|
|
|
for(int i=0; i<4; ++i)
|
|
{
|
|
OCIO_CHECK_CLOSE(vcombined[i], vout[i], tolerance);
|
|
}
|
|
}
|
|
|
|
{
|
|
float x[] = { 26.0f, -0.5f, 0.005f, 12.1f };
|
|
float vout[4];
|
|
|
|
float mout[16];
|
|
float vcombined[4];
|
|
OCIO::GetMxbCombine(mout, vout, m1, v1, m2, v2);
|
|
GetMxbResult(vcombined, mout, x, vout);
|
|
|
|
GetMxbResult(vout, m1, x, v1);
|
|
GetMxbResult(vout, m2, vout, v2);
|
|
|
|
// We pick a not so small tolerance, as we're dealing with
|
|
// large numbers, and the error for CHECK_CLOSE is absolute.
|
|
for(int i=0; i<4; ++i)
|
|
{
|
|
OCIO_CHECK_CLOSE(vcombined[i], vout[i], 1e-3);
|
|
}
|
|
}
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, mxb_invert)
|
|
{
|
|
{
|
|
float m[] = { 1.0f, 2.0f, 0.0f, 0.0f,
|
|
0.0f, 1.0f, 1.0f, 0.0f,
|
|
1.0f, 0.0f, 1.0f, 0.0f,
|
|
0.0f, 1.0f, 3.0f, 1.0f };
|
|
float x[] = { 1.0f, 0.5f, -1.0f, 60.0f };
|
|
float v[] = { 1.0f, 2.0f, 3.0f, 4.0f };
|
|
|
|
float vresult[4];
|
|
float mout[16];
|
|
float vout[4];
|
|
|
|
GetMxbResult(vresult, m, x, v);
|
|
bool invertsuccess = OCIO::GetMxbInverse(mout, vout, m, v);
|
|
OCIO_CHECK_EQUAL(invertsuccess, true);
|
|
|
|
GetMxbResult(vresult, mout, vresult, vout);
|
|
|
|
float tolerance = 1e-9f;
|
|
for(int i=0; i<4; ++i)
|
|
{
|
|
OCIO_CHECK_CLOSE(vresult[i], x[i], tolerance);
|
|
}
|
|
}
|
|
|
|
{
|
|
float m[] = { 0.3f, 0.3f, 0.3f, 0.0f,
|
|
0.3f, 0.3f, 0.3f, 0.0f,
|
|
0.3f, 0.3f, 0.3f, 0.0f,
|
|
0.0f, 0.0f, 0.0f, 1.0f };
|
|
float v[] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
float mout[16];
|
|
float vout[4];
|
|
|
|
bool invertsuccess = OCIO::GetMxbInverse(mout, vout, m, v);
|
|
OCIO_CHECK_EQUAL(invertsuccess, false);
|
|
}
|
|
}
|
|
|
|
|
|
// Infrastructure for testing FloatsDiffer()
|
|
//
|
|
#define KEEP_DENORMS false
|
|
#define COMPRESS_DENORMS true
|
|
|
|
#define TEST_CHECK_MESSAGE(a, msg) if(!(a)) throw OCIO::Exception(msg.c_str())
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
const float posinf = std::numeric_limits<float>::infinity();
|
|
const float neginf = -std::numeric_limits<float>::infinity();
|
|
const float qnan = std::numeric_limits<float>::quiet_NaN();
|
|
const float snan = std::numeric_limits<float>::signaling_NaN();
|
|
|
|
const float posmaxfloat = std::numeric_limits<float>::max();
|
|
const float negmaxfloat = -std::numeric_limits<float>::max();
|
|
|
|
const float posminfloat = std::numeric_limits<float>::min();
|
|
const float negminfloat = -std::numeric_limits<float>::min();
|
|
|
|
const float zero = 0.0f;
|
|
const float negzero = -0.0f;
|
|
|
|
const float posone = 1.0f;
|
|
const float negone = -1.0f;
|
|
|
|
const float posrandom = 12.345f;
|
|
const float negrandom = -12.345f;
|
|
|
|
// Helper macros to declare float variables close to a reference value.
|
|
// We use these variables to validate the threshold comparison of FloatsDiffer.
|
|
//
|
|
#define DECLARE_FLOAT(VAR_NAME, REFERENCE, ULP) \
|
|
const float VAR_NAME = OCIO::AddULP(REFERENCE, ULP)
|
|
|
|
#define DECLARE_FLOAT_PLUS_ULP(VAR_PREFIX, REFERENCE, ULP1, ULP2, ULP3, ULP4, ULP5, ULP6) \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP1, REFERENCE, ULP1); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP2, REFERENCE, ULP2); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP3, REFERENCE, ULP3); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP4, REFERENCE, ULP4); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP5, REFERENCE, ULP5); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP6, REFERENCE, ULP6)
|
|
|
|
#define DECLARE_FLOAT_MINUS_ULP(VAR_PREFIX, REFERENCE, ULP1, ULP2, ULP3, ULP4, ULP5, ULP6) \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP1, REFERENCE, -ULP1); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP2, REFERENCE, -ULP2); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP3, REFERENCE, -ULP3); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP4, REFERENCE, -ULP4); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP5, REFERENCE, -ULP5); \
|
|
DECLARE_FLOAT(VAR_PREFIX##ULP6, REFERENCE, -ULP6)
|
|
|
|
#define DECLARE_FLOAT_RANGE_ULP(VAR_PLUS_PREFIX, VAR_MINUS_PREFIX, REFERENCE, ULP1, ULP2, ULP3, ULP4, ULP5, ULP6) \
|
|
DECLARE_FLOAT_PLUS_ULP(VAR_PLUS_PREFIX, REFERENCE, ULP1, ULP2, ULP3, ULP4, ULP5, ULP6); \
|
|
DECLARE_FLOAT_MINUS_ULP(VAR_MINUS_PREFIX, REFERENCE, ULP1, ULP2, ULP3, ULP4, ULP5, ULP6)
|
|
|
|
// Create close float representations for comparison:
|
|
// Create new floats for (-/+) 1, tol/2, tol-1, tol, tol+1 and 2*tol ULPs.
|
|
const int tol = 8;
|
|
|
|
// posinf_p* => (NaN, NaN, NaN, NaN, NaN, NaN)
|
|
DECLARE_FLOAT_RANGE_ULP(posinf_p, posinf_m, posinf, 1, 4, 7, 8, 9, 16);
|
|
|
|
// neginf_p* => (-NaN, -NaN, -NaN, -NaN, -NaN, -NaN)
|
|
DECLARE_FLOAT_RANGE_ULP(neginf_p, neginf_m, neginf, 1, 4, 7, 8, 9, 16);
|
|
|
|
// posmaxfloat_p* => (+Inf, NaN, NaN, NaN, NaN, NaN)
|
|
DECLARE_FLOAT_RANGE_ULP(posmaxfloat_p, posmaxfloat_m, posmaxfloat, 1, 4, 7, 8, 9, 16);
|
|
|
|
// negmaxfloat_p* => (-Inf, -NaN, -NaN, -NaN, -NaN, -NaN)
|
|
DECLARE_FLOAT_RANGE_ULP(negmaxfloat_p, negmaxfloat_m, negmaxfloat, 1, 4, 7, 8, 9, 16);
|
|
|
|
// posminfloat_m* => denorms
|
|
DECLARE_FLOAT_RANGE_ULP(posminfloat_p, posminfloat_m, posminfloat, 1, 4, 7, 8, 9, 16);
|
|
|
|
// negminfloat_m* => -denorms
|
|
DECLARE_FLOAT_RANGE_ULP(negminfloat_p, negminfloat_m, negminfloat, 1, 4, 7, 8, 9, 16);
|
|
|
|
// zero_p* => denorms
|
|
DECLARE_FLOAT_PLUS_ULP(zero_p, zero, 1, 4, 7, 8, 9, 16);
|
|
|
|
// negzero_p* => -denorms
|
|
DECLARE_FLOAT_PLUS_ULP(negzero_p, negzero, 1, 4, 7, 8, 9, 16);
|
|
|
|
DECLARE_FLOAT_RANGE_ULP(posone_p, posone_m, posone, 1, 4, 7, 8, 9, 16);
|
|
DECLARE_FLOAT_RANGE_ULP(negone_p, negone_m, negone, 1, 4, 7, 8, 9, 16);
|
|
|
|
DECLARE_FLOAT_RANGE_ULP(posrandom_p, posrandom_m, posrandom, 1, 4, 7, 8, 9, 16);
|
|
DECLARE_FLOAT_RANGE_ULP(negrandom_p, negrandom_m, negrandom, 1, 4, 7, 8, 9, 16);
|
|
|
|
#undef DECLARE_FLOAT
|
|
#undef DECLARE_FLOAT_PLUS_ULP
|
|
#undef DECLARE_FLOAT_MINUS_ULP
|
|
#undef DECLARE_FLOAT_RANGE_ULP
|
|
|
|
//
|
|
// Helper functions to validate if (1 to 6) floating-point values are DIFFERENT
|
|
// from a reference value, within a given tolerance threshold, and considering
|
|
// that denormalized values are being compressed or kept.
|
|
//
|
|
std::string getErrorMessageDifferent(const float a,
|
|
const float b,
|
|
const int tolerance,
|
|
const bool compressDenorms)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "The values " << a << " "
|
|
<< "(" << std::hex << std::showbase << OCIO::FloatAsInt(a) << std::dec << ") "
|
|
<< "and " << b << " "
|
|
<< "(" << std::hex << std::showbase << OCIO::FloatAsInt(b) << std::dec << ") "
|
|
<< "are expected to be DIFFERENT within a tolerance of " << tolerance << " ULPs "
|
|
<< ( compressDenorms ? "(when compressing denormalized numbers)."
|
|
: "(when keeping denormalized numbers)." );
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
void checkFloatsAreDifferent(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a)
|
|
{
|
|
TEST_CHECK_MESSAGE(OCIO::FloatsDiffer(ref, a, tolerance, compressDenorms),
|
|
getErrorMessageDifferent(ref, a, tolerance, compressDenorms) );
|
|
|
|
TEST_CHECK_MESSAGE(OCIO::FloatsDiffer(a, ref, tolerance, compressDenorms),
|
|
getErrorMessageDifferent(a, ref, tolerance, compressDenorms) );
|
|
}
|
|
|
|
void checkFloatsAreDifferent(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b)
|
|
{
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, a);
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, b);
|
|
}
|
|
|
|
void checkFloatsAreDifferent(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b, const float c)
|
|
{
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, a, b);
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, c);
|
|
}
|
|
|
|
void checkFloatsAreDifferent(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b, const float c, const float d)
|
|
{
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, a, b, c);
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, d);
|
|
}
|
|
|
|
void checkFloatsAreDifferent(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b, const float c, const float d,
|
|
const float e)
|
|
{
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, a, b, c, d);
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, e);
|
|
}
|
|
|
|
void checkFloatsAreDifferent(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b, const float c, const float d,
|
|
const float e, const float f)
|
|
{
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, a, b, c, d, e);
|
|
checkFloatsAreDifferent(ref, tolerance, compressDenorms, f);
|
|
}
|
|
|
|
//
|
|
// Helper functions to validate if (1 to 6) floating-point values are CLOSE
|
|
// to a reference value, within a given tolerance threshold, and considering
|
|
// that denormalized values are being compressed or kept.
|
|
//
|
|
std::string getErrorMessageClose(const float a, const float b, const int tolerance,
|
|
const bool compressDenorms)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "The values " << a << " "
|
|
<< "(" << std::hex << std::showbase << OCIO::FloatAsInt(a) << std::dec << ") "
|
|
<< "and " << b << " "
|
|
<< "(" << std::hex << std::showbase << OCIO::FloatAsInt(b) << std::dec << ") "
|
|
<< "are expected to be CLOSE within a tolerance of " << tolerance << " ULPs "
|
|
<< ( compressDenorms ? "(when compressing denormalized numbers)."
|
|
: "(when keeping denormalized numbers)." );
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
void checkFloatsAreClose(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a)
|
|
{
|
|
TEST_CHECK_MESSAGE(!OCIO::FloatsDiffer(ref, a, tolerance, compressDenorms),
|
|
getErrorMessageClose(ref, a, tolerance, compressDenorms) );
|
|
|
|
TEST_CHECK_MESSAGE(!OCIO::FloatsDiffer(a, ref, tolerance, compressDenorms),
|
|
getErrorMessageClose(a, ref, tolerance, compressDenorms) );
|
|
}
|
|
|
|
void checkFloatsAreClose(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b)
|
|
{
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, a);
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, b);
|
|
}
|
|
|
|
void checkFloatsAreClose(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b, const float c)
|
|
{
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, a, b);
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, c);
|
|
}
|
|
|
|
void checkFloatsAreClose(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b, const float c, const float d)
|
|
{
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, a, b, c);
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, d);
|
|
}
|
|
|
|
void checkFloatsAreClose(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b, const float c, const float d,
|
|
const float e)
|
|
{
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, a, b, c, d);
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, e);
|
|
}
|
|
|
|
void checkFloatsAreClose(const float ref, const int tolerance, const bool compressDenorms,
|
|
const float a, const float b, const float c, const float d,
|
|
const float e, const float f)
|
|
{
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, a, b, c, d, e);
|
|
checkFloatsAreClose(ref, tolerance, compressDenorms, f);
|
|
}
|
|
|
|
//
|
|
// Helper functions to validate if 1 or 2 floating-point values are EQUAL
|
|
// to a reference value, considering that denormalized values are being
|
|
// compressed or kept.
|
|
//
|
|
std::string getErrorMessageEqual(const float a, const float b, const bool compressDenorms)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "The values " << a << " "
|
|
<< "(" << std::hex << std::showbase << OCIO::FloatAsInt(a) << std::dec << ") "
|
|
<< "and " << b << " "
|
|
<< "(" << std::hex << std::showbase << OCIO::FloatAsInt(b) << std::dec << ") "
|
|
<< "are expected to be EQUAL "
|
|
<< ( compressDenorms ? "(when compressing denormalized numbers)."
|
|
: "(when keeping denormalized numbers)." );
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
void checkFloatsAreEqual(const float ref, const bool compressDenorms, const float a)
|
|
{
|
|
TEST_CHECK_MESSAGE(!OCIO::FloatsDiffer(ref, a, 0, compressDenorms),
|
|
getErrorMessageEqual(ref, a, compressDenorms) );
|
|
|
|
TEST_CHECK_MESSAGE(!OCIO::FloatsDiffer(a, ref, 0, compressDenorms),
|
|
getErrorMessageEqual(a, ref, compressDenorms) );
|
|
}
|
|
|
|
void checkFloatsAreEqual(const float ref, const bool compressDenorms,
|
|
const float a, const float b)
|
|
{
|
|
checkFloatsAreEqual(ref, compressDenorms, a);
|
|
checkFloatsAreEqual(ref, compressDenorms, b);
|
|
}
|
|
|
|
// Validate a set of floating-point comparison that are expected to be
|
|
// unaffected by the "compress denormalized floats" flag.
|
|
void checkFloatsDenormInvariant(const bool compressDenorms)
|
|
{
|
|
checkFloatsAreEqual(posinf, compressDenorms, posinf);
|
|
checkFloatsAreDifferent(posinf, compressDenorms, tol, neginf, qnan, snan);
|
|
|
|
checkFloatsAreEqual(neginf, compressDenorms, neginf);
|
|
checkFloatsAreDifferent(neginf, compressDenorms, tol, qnan, snan);
|
|
|
|
checkFloatsAreEqual(qnan, compressDenorms, qnan, snan);
|
|
checkFloatsAreEqual(snan, compressDenorms, snan);
|
|
|
|
// Check positive infinity limits
|
|
//
|
|
checkFloatsAreDifferent(posinf, tol, compressDenorms,
|
|
posinf_p1, posinf_p4, posinf_p7,
|
|
posinf_p8, posinf_p9, posinf_p16);
|
|
|
|
checkFloatsAreDifferent(posinf, tol, compressDenorms,
|
|
posinf_m1, posinf_m4, posinf_m7,
|
|
posinf_m8, posinf_m9, posinf_m16);
|
|
|
|
// Check negative infinity limits
|
|
//
|
|
checkFloatsAreDifferent(neginf, tol, compressDenorms,
|
|
neginf_p1, neginf_p4, neginf_p7,
|
|
neginf_p8, neginf_p9, neginf_p16);
|
|
|
|
checkFloatsAreDifferent(neginf, tol, compressDenorms,
|
|
neginf_m1, neginf_m4, neginf_m7,
|
|
neginf_m8, neginf_m9, neginf_m16);
|
|
|
|
// Check positive maximum float
|
|
//
|
|
checkFloatsAreEqual(posmaxfloat, compressDenorms, posinf_m1);
|
|
checkFloatsAreEqual(posmaxfloat_p1, compressDenorms, posinf);
|
|
|
|
checkFloatsAreDifferent(posmaxfloat, tol, compressDenorms,
|
|
posmaxfloat_p1, posmaxfloat_p4, posmaxfloat_p7,
|
|
posmaxfloat_p8, posmaxfloat_p9, posmaxfloat_p16 );
|
|
|
|
checkFloatsAreClose(posmaxfloat, tol, compressDenorms,
|
|
posmaxfloat_m1, posmaxfloat_m4,
|
|
posmaxfloat_m7, posmaxfloat_m8);
|
|
|
|
checkFloatsAreDifferent(posmaxfloat, compressDenorms, tol, posmaxfloat_m9, posmaxfloat_m16 );
|
|
|
|
// Check negative maximum float
|
|
//
|
|
checkFloatsAreEqual(negmaxfloat, compressDenorms, neginf_m1);
|
|
checkFloatsAreEqual(negmaxfloat_p1, compressDenorms, neginf);
|
|
|
|
checkFloatsAreDifferent(negmaxfloat, tol, compressDenorms,
|
|
negmaxfloat_p1, negmaxfloat_p4, negmaxfloat_p7,
|
|
negmaxfloat_p8, negmaxfloat_p9, negmaxfloat_p16 );
|
|
|
|
checkFloatsAreClose(negmaxfloat, tol, compressDenorms,
|
|
negmaxfloat_m1, negmaxfloat_m4,
|
|
negmaxfloat_m7, negmaxfloat_m8);
|
|
|
|
checkFloatsAreDifferent(negmaxfloat, compressDenorms, tol, negmaxfloat_m9, negmaxfloat_m16 );
|
|
|
|
// Check zero and negative zero equality
|
|
checkFloatsAreEqual(zero, compressDenorms, negzero);
|
|
|
|
// Check positive and negative one
|
|
checkFloatsAreDifferent(posone, tol, compressDenorms, posone_m16, posone_m9);
|
|
checkFloatsAreClose(posone, tol, compressDenorms, posone_m8, posone_m7, posone_m4, posone_m1);
|
|
checkFloatsAreClose(posone, tol, compressDenorms, posone_p1, posone_p4, posone_p7, posone_p8);
|
|
checkFloatsAreDifferent(posone, tol, compressDenorms, posone_p9, posone_p16);
|
|
|
|
checkFloatsAreDifferent(negone, tol, compressDenorms, negone_m16, negone_m9);
|
|
checkFloatsAreClose(negone, tol, compressDenorms, negone_m8, negone_m7, negone_m4, negone_m1);
|
|
checkFloatsAreClose(negone, tol, compressDenorms, negone_p1, negone_p4, negone_p7, negone_p8);
|
|
checkFloatsAreDifferent(negone, tol, compressDenorms, negone_p9, negone_p16);
|
|
|
|
// Check positive and negative random value
|
|
checkFloatsAreDifferent(posrandom, tol, compressDenorms, posrandom_m16, posrandom_m9);
|
|
checkFloatsAreClose(posrandom, tol, compressDenorms,
|
|
posrandom_m8, posrandom_m7, posrandom_m4, posrandom_m1);
|
|
checkFloatsAreClose(posrandom, tol, compressDenorms,
|
|
posrandom_p1, posrandom_p4, posrandom_p7, posrandom_p8);
|
|
checkFloatsAreDifferent(posrandom, tol, compressDenorms, posrandom_p9, posrandom_p16);
|
|
|
|
checkFloatsAreDifferent(negrandom, tol, compressDenorms, negrandom_m16, negrandom_m9);
|
|
checkFloatsAreClose(negrandom, tol, compressDenorms,
|
|
negrandom_m8, negrandom_m7, negrandom_m4, negrandom_m1);
|
|
checkFloatsAreClose(negrandom, tol, compressDenorms, negrandom_p1,
|
|
negrandom_p4, negrandom_p7, negrandom_p8);
|
|
checkFloatsAreDifferent(negrandom, tol, compressDenorms, negrandom_p9, negrandom_p16);
|
|
}
|
|
|
|
} // anon
|
|
|
|
OCIO_ADD_TEST(MathUtils, float_diff_keep_denorms_test)
|
|
{
|
|
checkFloatsDenormInvariant(KEEP_DENORMS);
|
|
|
|
// Check positive minimum float
|
|
//
|
|
checkFloatsAreDifferent(posminfloat, tol, KEEP_DENORMS, posminfloat_m16, posminfloat_m9);
|
|
checkFloatsAreClose(posminfloat, tol, KEEP_DENORMS,
|
|
posminfloat_m8, posminfloat_m7,
|
|
posminfloat_m4, posminfloat_m1);
|
|
checkFloatsAreClose(posminfloat, tol, KEEP_DENORMS,
|
|
posminfloat_p1, posminfloat_p4,
|
|
posminfloat_p7, posminfloat_p8);
|
|
checkFloatsAreDifferent(posminfloat, tol, KEEP_DENORMS, posminfloat_p9, posminfloat_p16);
|
|
|
|
// Check negative minimum float
|
|
//
|
|
checkFloatsAreDifferent(negminfloat, tol, KEEP_DENORMS, negminfloat_m16, negminfloat_m9);
|
|
checkFloatsAreClose(negminfloat, tol, KEEP_DENORMS,
|
|
negminfloat_m8, negminfloat_m7,
|
|
negminfloat_m4, negminfloat_m1);
|
|
checkFloatsAreClose(negminfloat, tol, KEEP_DENORMS,
|
|
negminfloat_p1, negminfloat_p4,
|
|
negminfloat_p7, negminfloat_p8);
|
|
checkFloatsAreDifferent(negminfloat, tol, KEEP_DENORMS, negminfloat_p9, negminfloat_p16);
|
|
|
|
// Compare zero and positive denorms
|
|
checkFloatsAreClose(zero, tol, KEEP_DENORMS, zero_p1, zero_p4, zero_p7, zero_p8);
|
|
checkFloatsAreDifferent(zero, tol, KEEP_DENORMS, zero_p9, zero_p16);
|
|
|
|
// Compare zero and negative denorms
|
|
checkFloatsAreClose(zero, tol, KEEP_DENORMS, negzero_p1, negzero_p4, negzero_p7, negzero_p8);
|
|
checkFloatsAreDifferent(zero, tol, KEEP_DENORMS, negzero_p9, negzero_p16);
|
|
|
|
// Compare negative zero and positive denorms
|
|
checkFloatsAreClose(negzero, tol, KEEP_DENORMS, zero_p1, zero_p4, zero_p7, zero_p8);
|
|
checkFloatsAreDifferent(negzero, tol, KEEP_DENORMS, zero_p9, zero_p16);
|
|
|
|
// Compare negative zero and negative denorms
|
|
checkFloatsAreClose(negzero, tol, KEEP_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7, negzero_p8);
|
|
checkFloatsAreDifferent(negzero, tol, KEEP_DENORMS, negzero_p9, negzero_p16);
|
|
|
|
// Compare positive denorms and negative denorms
|
|
checkFloatsAreClose(zero_p1, tol, KEEP_DENORMS, negzero_p1, negzero_p4, negzero_p7);
|
|
checkFloatsAreDifferent(zero_p1, tol, KEEP_DENORMS, negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreClose(zero_p4, tol, KEEP_DENORMS, negzero_p1, negzero_p4);
|
|
checkFloatsAreDifferent(zero_p4, tol, KEEP_DENORMS,
|
|
negzero_p7, negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreDifferent(zero_p9, tol, KEEP_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreClose(negzero_p1, tol, KEEP_DENORMS, zero_p1, zero_p4, zero_p7);
|
|
checkFloatsAreDifferent(negzero_p1, tol, KEEP_DENORMS, zero_p8, zero_p9, zero_p16);
|
|
|
|
checkFloatsAreClose(negzero_p4, tol, KEEP_DENORMS, zero_p1, zero_p4);
|
|
checkFloatsAreDifferent(negzero_p4, tol, KEEP_DENORMS, zero_p7, zero_p8, zero_p9, zero_p16);
|
|
|
|
checkFloatsAreDifferent(negzero_p9, tol, KEEP_DENORMS,
|
|
zero_p1, zero_p4, zero_p7,
|
|
zero_p8, zero_p9, zero_p16);
|
|
|
|
// Compare negative and positive minimum floats
|
|
//
|
|
// Note: The float-point values being compared are expected to be different because there is
|
|
// the full set of denormalized values between zero and -/+MIN_FLOAT when denormalized
|
|
// values are kept.
|
|
checkFloatsAreDifferent(posminfloat, tol, KEEP_DENORMS, zero_p1, zero_p4, zero_p7,
|
|
zero_p8, zero_p9, zero_p16);
|
|
|
|
checkFloatsAreDifferent(posminfloat, tol, KEEP_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreDifferent(posminfloat, tol, KEEP_DENORMS,
|
|
negminfloat_p1, negminfloat_p4, negminfloat_p7,
|
|
negminfloat_p8, negminfloat_p9, negminfloat_p16);
|
|
|
|
checkFloatsAreDifferent(posminfloat, tol, KEEP_DENORMS,
|
|
negminfloat_m1, negminfloat_m4, negminfloat_m7,
|
|
negminfloat_m8, negminfloat_m9, negminfloat_m16);
|
|
|
|
checkFloatsAreDifferent(negminfloat, tol, KEEP_DENORMS, zero_p1, zero_p4, zero_p7,
|
|
zero_p8, zero_p9, zero_p16);
|
|
|
|
checkFloatsAreDifferent(negminfloat, tol, KEEP_DENORMS, negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreDifferent(negminfloat, tol, KEEP_DENORMS,
|
|
posminfloat_p1, posminfloat_p4, posminfloat_p7,
|
|
posminfloat_p8, posminfloat_p9, posminfloat_p16);
|
|
|
|
checkFloatsAreDifferent(negminfloat, tol, KEEP_DENORMS,
|
|
posminfloat_m1, posminfloat_m4, posminfloat_m7,
|
|
posminfloat_m8, posminfloat_m9, posminfloat_m16);
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, float_diff_compress_denorms_test )
|
|
{
|
|
checkFloatsDenormInvariant(COMPRESS_DENORMS);
|
|
|
|
// Check positive minimum float
|
|
//
|
|
// Note: posminfloat_m* are mapped to zero when compressing denormalized values.
|
|
checkFloatsAreClose(posminfloat, tol, COMPRESS_DENORMS,
|
|
posminfloat_m16, posminfloat_m9, posminfloat_m8,
|
|
posminfloat_m7, posminfloat_m4, posminfloat_m1);
|
|
checkFloatsAreClose(posminfloat, tol, COMPRESS_DENORMS,
|
|
posminfloat_p1, posminfloat_p4,
|
|
posminfloat_p7, posminfloat_p8);
|
|
checkFloatsAreDifferent(posminfloat, tol, COMPRESS_DENORMS, posminfloat_p9, posminfloat_p16);
|
|
|
|
// Check negative minimum float
|
|
//
|
|
// Note: negminfloat_m* are mapped to zero when compressing denormalized values.
|
|
checkFloatsAreClose(negminfloat, tol, COMPRESS_DENORMS,
|
|
negminfloat_m16, negminfloat_m9, negminfloat_m8,
|
|
negminfloat_m7, negminfloat_m4, negminfloat_m1);
|
|
checkFloatsAreClose(negminfloat, tol, COMPRESS_DENORMS,
|
|
negminfloat_p1, negminfloat_p4,
|
|
negminfloat_p7, negminfloat_p8);
|
|
checkFloatsAreDifferent(negminfloat, tol, COMPRESS_DENORMS, negminfloat_p9, negminfloat_p16);
|
|
|
|
// Compare zero and positive denorms
|
|
//
|
|
// Note: zero_p* are mapped to zero when compressing denormalized values.
|
|
checkFloatsAreClose(zero, tol, COMPRESS_DENORMS,
|
|
zero_p1, zero_p4, zero_p7, zero_p8, zero_p9, zero_p16);
|
|
|
|
// Compare zero and negative denorms
|
|
//
|
|
// Note: negzero_p* are mapped to zero when compressing denormalized values.
|
|
checkFloatsAreClose(zero, tol, COMPRESS_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
// Compare negative zero and positive denorms
|
|
//
|
|
// Note: zero_p* are mapped to zero when compressing denormalized values.
|
|
checkFloatsAreClose(negzero, tol, COMPRESS_DENORMS,
|
|
zero_p1, zero_p4, zero_p7, zero_p8, zero_p9, zero_p16);
|
|
|
|
// Compare negative zero and negative denorms
|
|
//
|
|
// Note: negzero_p* are mapped to zero when compressing denormalized values.
|
|
checkFloatsAreClose(negzero, tol, COMPRESS_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
// Compare positive denorms and negative denorms
|
|
//
|
|
// Note: negzero_p* are mapped to zero when compressing denormalized values.
|
|
checkFloatsAreClose(zero_p1, tol, COMPRESS_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreClose(zero_p4, tol, COMPRESS_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreClose(zero_p9, tol, COMPRESS_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreClose(negzero_p1, tol, COMPRESS_DENORMS,
|
|
zero_p1, zero_p4, zero_p7, zero_p8, zero_p9, zero_p16);
|
|
|
|
checkFloatsAreClose(negzero_p4, tol, COMPRESS_DENORMS,
|
|
zero_p1, zero_p4, zero_p7, zero_p8, zero_p9, zero_p16);
|
|
|
|
checkFloatsAreClose(negzero_p9, tol, COMPRESS_DENORMS,
|
|
zero_p1, zero_p4, zero_p7, zero_p8, zero_p9, zero_p16);
|
|
|
|
// Compare negative and positive minimum floats
|
|
//
|
|
// Note: When compressing denorms, the mapped floating-point values ordering used for
|
|
// comparison becomes: ... , negminfloat , zero , posminfloat , ..., so the
|
|
// difference between negminfloat and posminfloat actually becomes 2 ULPs.
|
|
// Denormalized values like, zero_p*, negzero_p*, posminfloat_m*, negminfloat_m*
|
|
// are all mapped to zero.
|
|
checkFloatsAreClose(zero, 1, COMPRESS_DENORMS, negminfloat);
|
|
checkFloatsAreClose(zero, 1, COMPRESS_DENORMS, posminfloat);
|
|
checkFloatsAreClose(posminfloat, 2, COMPRESS_DENORMS, negminfloat);
|
|
|
|
checkFloatsAreClose(posminfloat, tol, COMPRESS_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreClose(posminfloat, tol, COMPRESS_DENORMS, negminfloat_p1, negminfloat_p4);
|
|
checkFloatsAreDifferent(posminfloat, tol, COMPRESS_DENORMS,
|
|
negminfloat_p7, negminfloat_p8,
|
|
negminfloat_p9, negminfloat_p16);
|
|
|
|
checkFloatsAreClose(posminfloat, tol, COMPRESS_DENORMS,
|
|
negminfloat_m1, negminfloat_m4, negminfloat_m7,
|
|
negminfloat_m8, negminfloat_m9, negminfloat_m16);
|
|
|
|
checkFloatsAreClose(negminfloat, tol, COMPRESS_DENORMS,
|
|
zero_p1, zero_p4, zero_p7, zero_p8, zero_p9, zero_p16);
|
|
|
|
checkFloatsAreClose(negminfloat, tol, COMPRESS_DENORMS,
|
|
negzero_p1, negzero_p4, negzero_p7,
|
|
negzero_p8, negzero_p9, negzero_p16);
|
|
|
|
checkFloatsAreClose(negminfloat, tol, COMPRESS_DENORMS, posminfloat_p1, posminfloat_p4);
|
|
checkFloatsAreDifferent(negminfloat, tol, COMPRESS_DENORMS,
|
|
posminfloat_p7, posminfloat_p8,
|
|
posminfloat_p9, posminfloat_p16);
|
|
|
|
checkFloatsAreClose(negminfloat, tol, COMPRESS_DENORMS,
|
|
posminfloat_m1, posminfloat_m4, posminfloat_m7,
|
|
posminfloat_m8, posminfloat_m9, posminfloat_m16);
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, half_bits_test)
|
|
{
|
|
// Validation.
|
|
OCIO_CHECK_EQUAL(0.5f, OCIO::ConvertHalfBitsToFloat(0x3800));
|
|
|
|
// Preserve negatives.
|
|
OCIO_CHECK_EQUAL(-1.f, OCIO::ConvertHalfBitsToFloat(0xbc00));
|
|
|
|
// Preserve values > 1.
|
|
OCIO_CHECK_EQUAL(1024.f, OCIO::ConvertHalfBitsToFloat(0x6400));
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, halfs_differ_test)
|
|
{
|
|
half pos_inf; pos_inf.setBits(31744); // +inf
|
|
half neg_inf; neg_inf.setBits(64512); // -inf
|
|
half pos_nan; pos_nan.setBits(31745); // +nan
|
|
half neg_nan; neg_nan.setBits(64513); // -nan
|
|
half pos_max; pos_max.setBits(31743); // +HALF_MAX
|
|
half neg_max; neg_max.setBits(64511); // -HALF_MAX
|
|
half pos_zero; pos_zero.setBits(0); // +0
|
|
half neg_zero; neg_zero.setBits(32768); // -0
|
|
half pos_small; pos_small.setBits(4); // +small
|
|
half neg_small; neg_small.setBits(32772); // -small
|
|
half pos_1; pos_1.setBits(15360); //
|
|
half pos_2; pos_2.setBits(15365); //
|
|
half neg_1; neg_1.setBits(50000); //
|
|
half neg_2; neg_2.setBits(50005); //
|
|
|
|
int tol = 10;
|
|
|
|
OCIO_CHECK_ASSERT(OCIO::HalfsDiffer(pos_inf, neg_inf, tol));
|
|
OCIO_CHECK_ASSERT(OCIO::HalfsDiffer(pos_inf, pos_nan, tol));
|
|
OCIO_CHECK_ASSERT(OCIO::HalfsDiffer(neg_inf, neg_nan, tol));
|
|
OCIO_CHECK_ASSERT(OCIO::HalfsDiffer(pos_max, pos_inf, tol));
|
|
OCIO_CHECK_ASSERT(OCIO::HalfsDiffer(neg_max, neg_inf, tol));
|
|
OCIO_CHECK_ASSERT(OCIO::HalfsDiffer(pos_1, neg_1, tol));
|
|
OCIO_CHECK_ASSERT(OCIO::HalfsDiffer(pos_2, pos_1, 0));
|
|
OCIO_CHECK_ASSERT(OCIO::HalfsDiffer(neg_2, neg_1, 0));
|
|
|
|
OCIO_CHECK_ASSERT(!OCIO::HalfsDiffer(pos_zero, neg_zero, 0));
|
|
OCIO_CHECK_ASSERT(!OCIO::HalfsDiffer(pos_small, neg_small, tol));
|
|
OCIO_CHECK_ASSERT(!OCIO::HalfsDiffer(pos_2, pos_1, tol));
|
|
OCIO_CHECK_ASSERT(!OCIO::HalfsDiffer(neg_2, neg_1, tol));
|
|
}
|
|
|
|
OCIO_ADD_TEST(MathUtils, clamp)
|
|
{
|
|
OCIO_CHECK_EQUAL(-1.0f, OCIO::Clamp(std::numeric_limits<float>::quiet_NaN(), -1.0f, 1.0f));
|
|
|
|
OCIO_CHECK_EQUAL(10.0f, OCIO::Clamp( std::numeric_limits<float>::infinity(), 5.0f, 10.0f));
|
|
OCIO_CHECK_EQUAL(5.0f, OCIO::Clamp(-std::numeric_limits<float>::infinity(), 5.0f, 10.0f));
|
|
|
|
OCIO_CHECK_EQUAL(0.0000005f, OCIO::Clamp( 0.0000005f, 0.0f, 1.0f));
|
|
OCIO_CHECK_EQUAL(0.0f, OCIO::Clamp(-0.0000005f, 0.0f, 1.0f));
|
|
OCIO_CHECK_EQUAL(1.0f, OCIO::Clamp( 1.0000005f, 0.0f, 1.0f));
|
|
}
|
|
|