equal floats with tolerance

This commit is contained in:
BlackMATov
2020-12-06 23:15:08 +07:00
parent b0659e9239
commit 5fe1aab5b6
5 changed files with 29 additions and 11 deletions

View File

@@ -431,25 +431,36 @@ namespace vmath_hpp
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr equal_to(T x, T y) noexcept {
if constexpr ( std::is_floating_point_v<T> ) {
// http://www.realtimecollisiondetection.net/pubs/Tolerances
const T epsilon = std::numeric_limits<T>::epsilon();
return abs(x - y) <= epsilon * max(T(1), abs(x), abs(y));
} else {
return x == y;
}
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr equal_to(T x, T y, T epsilon) noexcept {
if constexpr ( std::is_floating_point_v<T> ) {
// http://www.realtimecollisiondetection.net/pubs/Tolerances
return abs(x - y) <= epsilon * max(T(1), abs(x), abs(y));
} else {
return abs(x - y) <= epsilon;
}
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr not_equal_to(T x, T y) noexcept {
return x != y;
return !equal_to(x, y);
}
template < typename T >
[[nodiscard]] std::enable_if_t<std::is_arithmetic_v<T>, bool>
constexpr not_equal_to(T x, T y, T epsilon) noexcept {
return abs(x - y) > epsilon;
return !equal_to(x, y, epsilon);
}
template < typename T >

View File

@@ -11,6 +11,7 @@
#include <initializer_list>
#include <iterator>
#include <limits>
#include <stdexcept>
#include <type_traits>
#include <utility>

View File

@@ -340,9 +340,7 @@ namespace vmath_hpp
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator!=(const mat<T, Size>& xs, const mat<T, Size>& ys) {
return fold_join([](bool acc, const vec<T, Size>& x, const vec<T, Size>& y){
return acc || (x != y);
}, false, xs, ys);
return !(xs == ys);
}
// operator<

View File

@@ -293,15 +293,13 @@ namespace vmath_hpp
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator==(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return fold_join([](bool acc, T x, T y){
return acc && (x == y);
return acc && equal_to(x, y);
}, true, xs, ys);
}
template < typename T, std::size_t Size >
[[nodiscard]] constexpr bool operator!=(const vec<T, Size>& xs, const vec<T, Size>& ys) {
return fold_join([](bool acc, T x, T y){
return acc || (x != y);
}, false, xs, ys);
return !(xs == ys);
}
// operator<

View File

@@ -165,6 +165,16 @@ TEST_CASE("vmath/fun") {
STATIC_REQUIRE_FALSE(not_equal_to(1, 1, 0));
STATIC_REQUIRE_FALSE(not_equal_to(1, 1, 1));
STATIC_REQUIRE(equal_to(1.f, 1.f + std::numeric_limits<float>::epsilon() * 0.5f));
STATIC_REQUIRE_FALSE(equal_to(1.f, 1.f + std::numeric_limits<float>::epsilon() * 1.5f));
STATIC_REQUIRE(equal_to(100.f, 100.f + std::numeric_limits<float>::epsilon() * 90.f));
STATIC_REQUIRE_FALSE(equal_to(100.f, 100.f + std::numeric_limits<float>::epsilon() * 110.f));
STATIC_REQUIRE_FALSE(not_equal_to(1.f, 1.f + std::numeric_limits<float>::epsilon() * 0.5f));
STATIC_REQUIRE(not_equal_to(1.f, 1.f + std::numeric_limits<float>::epsilon() * 1.5f));
STATIC_REQUIRE_FALSE(not_equal_to(100.f, 100.f + std::numeric_limits<float>::epsilon() * 90.f));
STATIC_REQUIRE(not_equal_to(100.f, 100.f + std::numeric_limits<float>::epsilon() * 110.f));
STATIC_REQUIRE_FALSE(any(false));
STATIC_REQUIRE_FALSE(any(0));
STATIC_REQUIRE(any(true));