| 7 | |
| 8 | template <typename Float> |
| 9 | bool AlmostEqualULPs(Float x, Float y, uint32_t maxULPs) |
| 10 | { |
| 11 | static_assert(std::is_floating_point<Float>::value, ""); |
| 12 | static_assert(std::numeric_limits<Float>::is_iec559, ""); |
| 13 | |
| 14 | // Make sure maxUlps is non-negative and small enough that the |
| 15 | // default NaN won't compare as equal to anything. |
| 16 | ASSERT_LESS(maxULPs, 4 * 1024 * 1024, ()); |
| 17 | |
| 18 | int constexpr bits = CHAR_BIT * sizeof(Float); |
| 19 | typedef typename boost::int_t<bits>::exact IntType; |
| 20 | typedef typename boost::uint_t<bits>::exact UIntType; |
| 21 | |
| 22 | // Same as *reinterpret_cast<IntType const *>(&x), but without warnings. |
| 23 | IntType xInt, yInt; |
| 24 | static_assert(sizeof(xInt) == sizeof(x), "bit_cast impossible"); |
| 25 | std::memcpy(&xInt, &x, sizeof(x)); |
| 26 | std::memcpy(&yInt, &y, sizeof(y)); |
| 27 | |
| 28 | // Make xInt and yInt lexicographically ordered as a twos-complement int. |
| 29 | IntType const highestBit = IntType(1) << (bits - 1); |
| 30 | if (xInt < 0) |
| 31 | xInt = highestBit - xInt; |
| 32 | if (yInt < 0) |
| 33 | yInt = highestBit - yInt; |
| 34 | |
| 35 | // Calculate diff with special case to avoid IntType overflow. |
| 36 | UIntType diff; |
| 37 | if ((xInt >= 0) == (yInt >= 0)) |
| 38 | diff = math::Abs(xInt - yInt); |
| 39 | else |
| 40 | diff = UIntType(math::Abs(xInt)) + UIntType(math::Abs(yInt)); |
| 41 | |
| 42 | return diff <= maxULPs; |
| 43 | } |
| 44 | |
| 45 | template bool AlmostEqualULPs<float>(float x, float y, uint32_t maxULPs); |
| 46 | template bool AlmostEqualULPs<double>(double x, double y, uint32_t maxULPs); |