#include "math.hpp" #include <boost/integer.hpp> #include <cstring> #include <limits> namespace base { template <typename Float> bool AlmostEqualULPs(Float x, Float y, uint32_t maxULPs) { static_assert(std::is_floating_point<Float>::value, ""); static_assert(std::numeric_limits<Float>::is_iec559, ""); // 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, ()); int constexpr bits = CHAR_BIT * sizeof(Float); typedef typename boost::int_t<bits>::exact IntType; typedef typename boost::uint_t<bits>::exact UIntType; // Same as *reinterpret_cast<IntType const *>(&x), but without warnings. IntType xInt, yInt; static_assert(sizeof(xInt) == sizeof(x), "bit_cast impossible"); std::memcpy(&xInt, &x, sizeof(x)); std::memcpy(&yInt, &y, sizeof(y)); // Make xInt and yInt lexicographically ordered as a twos-complement int. IntType const highestBit = IntType(1) << (bits - 1); if (xInt < 0) xInt = highestBit - xInt; if (yInt < 0) yInt = highestBit - yInt; // Calculate diff with special case to avoid IntType overflow. UIntType diff; if ((xInt >= 0) == (yInt >= 0)) diff = Abs(xInt - yInt); else diff = UIntType(Abs(xInt)) + UIntType(Abs(yInt)); return diff <= maxULPs; } template bool AlmostEqualULPs<float>(float x, float y, uint32_t maxULPs); template bool AlmostEqualULPs<double>(double x, double y, uint32_t maxULPs); } // namespace base