I am trying to make a function for floating point numbers comparison.
The goal is to "evaluate" all operators in single function: >, >=, =, <=, <.
If X>Y, then F>0. If X==Y, F==0. If X<=Y, F<=0 etc (where F is returned value).
I took a piece of code from numeric limits. First thing I changed, in scaling of epsilon, fabs(x+y) to fabs(x)+fabs(y) (because if x=-y, we would be comparing diff to 0; which probably would work fine, but sounds kinda stupid). I've also seen an approach using max(fabs(x), fabs(y)), can we say that one of them is better than the others?
Third parameter, DecadesOfInAccuracy, means how many digits above epsilon() should be ignored.
#include <limits>
#include <iostream>
template<class T>
typename std::enable_if<!std::numeric_limits<T>::is_integer, int>::type
cmp(T x, T y, unsigned int doia = 0)
{
std::cout << "X: " << x << std::endl;
std::cout << "Y: " << y << std::endl;
std::cout << "D: " << fabs(x - y) << std::endl;
std::cout << "M: " << std::numeric_limits<double>::min() * pow(10, doia+1) << std::endl;
std::cout << "E: " << std::numeric_limits<T>::epsilon() * (fabs(x) + fabs(y)) * pow(10, doia + 1) << std::endl;
if (fabs(x - y) < std::numeric_limits<double>::min() * pow(10, doia + 1))
return 0;
bool ltoeq = (x - y) <= std::numeric_limits<T>::epsilon() * (fabs(x)+fabs(y)) * pow(10, doia + 1);
bool gtoeq = (y - x) <= std::numeric_limits<T>::epsilon() * (fabs(x) + fabs(y)) * pow(10, doia + 1);
std::cout << "L: " << ltoeq << std::endl;
std::cout << "G: " << gtoeq << std::endl;
return gtoeq - ltoeq;
}
int main()
{
std::cout.precision(std::numeric_limits<double>::max_digits10 + 5);
double x = 0.0001000000000000001;
double y = 0.0001;
int res = cmp(x, y, 0);
std::cout << res << std::endl << std::endl;
if (res > 0)
std::cout << "X>Y" << std::endl;
if (res >= 0)
std::cout << "X>=Y" << std::endl;
if (res == 0)
std::cout << "X==Y" << std::endl;
if (res <= 0)
std::cout << "X<=Y" << std::endl;
if (res < 0)
std::cout << "X<Y" << std::endl;
return 0;
}
It "correctly" returns equality for pairs like 0.0001000000000000001; 0.0001, 1.0-4*0.2; 0.2, 0; -0, 100000000000.0001; 100000000000.
Is there something I forgot to consider, or maybe something can be simplified? (of course except couts, which will be removed :P).
I am using VS2019 if that matters.