Skip to content

Instantly share code, notes, and snippets.

@vladiant
Created March 21, 2022 20:42
Show Gist options
  • Save vladiant/465f949c50a2739765faa7748b04d9c8 to your computer and use it in GitHub Desktop.
Save vladiant/465f949c50a2739765faa7748b04d9c8 to your computer and use it in GitHub Desktop.
Evolving a Nice Trick - Patrice Roy - CppCon 2021
#include <cmath>
class exact {};
class floating {};
template <class T> bool close_enough(T a, T b, exact) {
return a == b;
}
template <class T> bool close_enough(T a, T b, floating) {
return std::abs(a - b) <= static_cast<T>(0.000001);
}
struct false_type { enum { value = false }; };
struct true_type { enum { value = true }; };
template <class> struct is_floating : false_type { };
template <> struct is_floating<float> : true_type { };
template <> struct is_floating<double> : true_type { };
template <> struct is_floating<long double> : true_type { };
template <bool, class T, class F> struct static_if_else;
template <class T, class F> struct static_if_else<true, T, F> {
typedef T type;
};
template <class T, class F> struct static_if_else<false, T, F> {
typedef F type;
};
template <class T>
bool close_enough(T a, T b) { return close_enough(a, b, typename static_if_else<is_floating<T>::value, floating, exact>::type{}); }
int main() {
return close_enough(3,3) &&
close_enough(3.0,3.000000001);
}
#include <cmath>
#include <type_traits>
class exact {};
class floating {};
template <class T> bool close_enough(T a, T b, exact) {
return a == b;
}
template <class T> bool close_enough(T a, T b, floating) {
return std::abs(a - b) <= static_cast<T>(0.000001);
}
template <class T>
bool close_enough(T a, T b) {
return close_enough(a, b, typename std::conditional<std::is_floating_point<T>::value, floating, exact>::type{});
}
int main() {
return close_enough(3,3) &&
close_enough(3.0,3.000000001);
}
#include <type_traits>
class exact {};
class floating {};
template <class T> constexpr bool close_enough(T a, T b, exact) { return a == b; }
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; }
template <class T> constexpr bool close_enough(T a, T b, floating) {
return absolute(a - b) <= static_cast<T>(0.000001);
}
template <class T>
constexpr bool close_enough(T a, T b) {
return close_enough(a, b, typename std::conditional<
std::is_floating_point<T>::value, floating, exact
>::type{});
}
int main() {
static_assert(close_enough(3,3), "");
static_assert(close_enough(3.0,3.000000001));
}
#include <type_traits>
template <class T>
constexpr typename std::enable_if<!std::is_floating_point<T>::value, bool>::type
close_enough(T a, T b) {
return a == b;
}
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; }
template <class T>
constexpr typename std::enable_if<std::is_floating_point<T>::value, bool>::type
close_enough(T a, T b) {
return absolute(a - b) <= static_cast<T>(0.000001);
}
int main() {
static_assert(close_enough(3,3), "");
static_assert(close_enough(3.0,3.000000001));
}
#include <type_traits>
template <class T>
constexpr std::enable_if_t<!std::is_floating_point<T>::value, bool>
close_enough(T a, T b) { return a == b; }
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; }
template <class T> constexpr auto threshold = static_cast<T>(0.000001);
template <class T>
constexpr std::enable_if_t<std::is_floating_point<T>::value, bool>
close_enough(T a, T b) {
return absolute(a - b) <= threshold<T>;
}
int main() {
static_assert(close_enough(3,3), "");
static_assert(close_enough(3.0,3.000000001));
}
#include <type_traits>
template <class T>
constexpr std::enable_if_t<!std::is_floating_point_v<T>, bool>
close_enough(T a, T b) { return a == b; }
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; }
template <class T> constexpr auto threshold = static_cast<T>(0.000001);
template <class T>
constexpr std::enable_if_t<std::is_floating_point_v<T>, bool>
close_enough(T a, T b) {
return absolute(a - b) <= threshold<T>;
}
int main() {
static_assert(close_enough(3,3), "");
static_assert(close_enough(3.0,3.000000001));
}
#include <type_traits>
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; }
template <class T> constexpr auto threshold = static_cast<T>(0.000001);
template <class T>
constexpr bool close_enough(T a, T b) {
if constexpr(std::is_floating_point_v<T>)
return absolute(a - b) <= threshold<T>;
else
return a == b;
}
int main() {
static_assert(close_enough(3,3), "");
static_assert(close_enough(3.0,3.000000001));
}
#include <type_traits>
#include <concepts>
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; }
template <class T> constexpr auto threshold = static_cast<T>(0.000001);
template <class T> requires std::integral<T>
constexpr bool close_enough(T a, T b) {
return a == b;
}
template <class T> requires std::floating_point<T>
constexpr bool close_enough(T a, T b) {
return absolute(a - b) <= threshold<T>;
}
int main() {
static_assert(close_enough(3,3), "");
static_assert(close_enough(3.0,3.000000001));
}
#include <type_traits>
#include <concepts>
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; }
template <class T> constexpr auto threshold = static_cast<T>(0.000001);
template <std::integral T>
constexpr bool close_enough(T a, T b) {
return a == b;
}
template <std::floating_point T>
constexpr bool close_enough(T a, T b) {
return absolute(a - b) <= threshold<T>;
}
int main() {
static_assert(close_enough(3,3), "");
static_assert(close_enough(3.0,3.000000001));
}
#include <type_traits>
#include <concepts>
template <class T> constexpr T absolute(T val) { return val < 0? -val : val; }
template <class T> constexpr auto threshold = static_cast<T>(0.000001);
constexpr bool close_enough(std::integral auto a, std::integral auto b) {
return a == b;
}
constexpr bool close_enough(std::floating_point auto a, std::floating_point auto b) {
return absolute(a - b) <= threshold<
std::common_type_t<decltype(a), decltype(b)>
>;
}
int main() {
static_assert(close_enough(3,3), "");
static_assert(close_enough(3.0,3.000000001));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment