I understood that std::numeric_limits::espsilon() and DBL_EPSILON should deliver the same value but are defined in different headers, limits, and cfloat. Which makes std::numeric_limits::espsilon() a c style way of writing and DBL_EPSILON the c style.
My question is if there is any benefit in using std::numeric_limits::espsilon() over DBL_EPSILON in c project? Aside from a clean c coding style. Or did I understand this completely wrong?
CodePudding user response:
Here on this page https://en.cppreference.com/w/cpp/types/numeric_limits you can find tables of what are the C marco equivalents of the std::numeric_limits
.
They are equivalents, so for any pair of std::limits
function/constant and C macro you find in the table, they can be interchanged.
The big difference is in generic code:
template <typename T>
void foo() {
std::cout << std::numeric_limits<T>::epsilon();
}
Doing the same with C macros would require to write much more code. Also any opportunity to not use a macro is a good one.
CodePudding user response:
First of all DBL_EPSILON
is a C API so it is a good practice to use C specific API in C code. I know it is more typing, still it is a good practice. In my code when I need epsilon
multiple times for single type, I just bind it to some constexpr
.
More important thing this is a great tool when you write a template. For example:
template<std::floating_point T>
bool fuzzyCompare(T a, T b)
{
return std::fabs(a - b) <= 4 * std::max(std::fabs(a), std::fabs(b)) * std::numeric_limits<T>::espsilon();
}
CodePudding user response:
One obvious advantage of using std::numeric_limits<T>::epsilon
is generic function. Imagine if you write some function like an almost-equal. This function should accept floating numbers of different precisions, including double
, float
, long double
. Or maybe even integer types as well. To write this with the macro solution, you would have to write an overload for each of the floating point types:
bool almost_equal(float a, float b, int k)
{
return std::abs(a - b) <= FLT_EPSILON * std::abs(a b) * k;
}
bool almost_equal(double a, double b, int k)
{
return std::abs(a - b) <= DBL_EPSILON * std::abs(a b) * k;
}
...
But with the numeric_limits
template, you can simply write a single function for all of them:
template<typename T>
bool almost_equal(T a, T b, int k)
{
return std::abs(a - b) <= std::numeric_limits<T>::epsilon() * std::abs(a b) * k;
}