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.