From 5dec38415e1fa3cda43946f362112f09d5cae9b7 Mon Sep 17 00:00:00 2001 From: vng Date: Wed, 26 Jan 2011 21:25:12 +0200 Subject: [PATCH] Fix AlmostEqual. Add more unit tests. --- base/base_tests/math_test.cpp | 12 ++++++++++++ base/math.hpp | 17 +++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/base/base_tests/math_test.cpp b/base/base_tests/math_test.cpp index f26a28712e..b3e2b7c8de 100644 --- a/base/base_tests/math_test.cpp +++ b/base/base_tests/math_test.cpp @@ -45,9 +45,21 @@ UNIT_TEST(AlmostEqual_Smoke) TEST_ALMOST_EQUAL(+0.0, -0.0, ()); double const eps = numeric_limits::epsilon(); + double const dmax = numeric_limits::max(); + TEST_ALMOST_EQUAL(1.0 + eps, 1.0, ()); TEST_ALMOST_EQUAL(1.0 - eps, 1.0, ()); TEST_ALMOST_EQUAL(1.0 - eps, 1.0 + eps, ()); + + TEST_ALMOST_EQUAL(dmax, dmax, ()); + TEST_ALMOST_EQUAL(-dmax, -dmax, ()); + TEST_ALMOST_EQUAL(dmax/2.0, dmax/2.0, ()); + TEST_ALMOST_EQUAL(1.0/dmax, 1.0/dmax, ()); + TEST_ALMOST_EQUAL(-1.0/dmax, -1.0/dmax, ()); + + TEST(!my::AlmostEqual(1.0, -1.0), ()); + TEST(!my::AlmostEqual(2.0, -2.0), ()); + TEST(!my::AlmostEqual(dmax, -dmax), ()); } namespace diff --git a/base/math.hpp b/base/math.hpp index 7e98ed501e..413a81f305 100644 --- a/base/math.hpp +++ b/base/math.hpp @@ -1,9 +1,11 @@ #pragma once -#include "../base/assert.hpp" #include "../base/base.hpp" +#include "../base/assert.hpp" + #include "../std/cmath.hpp" #include "../std/limits.hpp" #include "../std/type_traits.hpp" + #include namespace my @@ -20,25 +22,28 @@ template bool AlmostEqual(FloatT x, FloatT y, unsigned int max STATIC_ASSERT(numeric_limits::is_iec559); STATIC_ASSERT(!numeric_limits::is_exact); STATIC_ASSERT(!numeric_limits::is_integer); + // Make sure maxUlps is non-negative and small enough that the // default NAN won't compare as equal to anything. ASSERT_LESS(maxULPs, 4 * 1024 * 1024, ()); - typedef typename boost::int_t<8 * sizeof(FloatT)>::exact IntType; + int const bits = 8 * sizeof(FloatT); + typedef typename boost::int_t::exact IntType; + typedef typename boost::uint_t::exact UIntType; IntType xInt = *reinterpret_cast(&x); IntType yInt = *reinterpret_cast(&y); // Make xInt and yInt lexicographically ordered as a twos-complement int - IntType const highestBit = IntType(1) << (sizeof(FloatT) * 8 - 1); + IntType const highestBit = IntType(1) << (bits - 1); if (xInt < 0) xInt = highestBit - xInt; if (yInt < 0) yInt = highestBit - yInt; - IntType const diff = Abs(xInt - yInt); + UIntType const diff = Abs(xInt - yInt); - return diff <= static_cast(maxULPs); + return (diff <= maxULPs); } template inline TFloat DegToRad(TFloat deg) @@ -72,7 +77,7 @@ template inline T clamp(T x, TMinMax xmin, TMinMa template inline T Abs(T x) { - return x >= 0 ? x : -x; + return (x < 0 ? -x : x); } template inline bool between_s(T a, T b, T x)