#include <cmath>
#include <concepts>
template <std::floating_point Type>
struct tolerances final {
static constexpr Type absolute_tolerance{ 0 };
static constexpr Type relative_tolerance{ 1e-9 };
};
template <std::floating_point Type>
constexpr bool is_close(const Type a, const Type b, const Type absolute_tolerance, const Type relative_tolerance) {
if (a == b)
{
return true;
}
if (std::isinf(a) || std::isinf(b))
{
return false;
}
const auto difference = std::fabs(b - a);
return difference <= std::fabs(relative_tolerance * b) ||
difference <= std::fabs(relative_tolerance * a) ||
difference <= absolute_tolerance;
}
template <std::floating_point Type>
constexpr bool is_close(const Type a, const Type b, const Type absolute_tolerance) {
return is_close(a, b, absolute_tolerance, tolerances<Type>::relative_tolerance);
}
template <std::floating_point Type>
constexpr bool is_close(const Type a, const Type b) {
return is_close(a, b, tolerances<Type>::absolute_tolerance, tolerances<Type>::relative_tolerance);
}
template <std::floating_point Type>
constexpr bool is_almost_equal(const Type a, const Type b, const Type absolute_tolerance) {
if (a == b)
{
return true;
}
if (std::isinf(a) || std::isinf(b))
{
return false;
}
return std::fabs(b - a) <= absolute_tolerance;
}
template <std::floating_point Type>
constexpr bool is_almost_zero(const Type a, const Type absolute_tolerance) {
return is_almost_equal(a, Type{ 0 }, absolute_tolerance);
}