Skip to content

Instantly share code, notes, and snippets.

@derofim
Created August 27, 2016 10:03
Show Gist options
  • Save derofim/b03cb371688bccbb37cead77b5f8f053 to your computer and use it in GitHub Desktop.
Save derofim/b03cb371688bccbb37cead77b5f8f053 to your computer and use it in GitHub Desktop.
floating point compare

GCC 6.1:

d1 is 0.200000003, d2 is 0.2000001073 d1 != d2 d1 almost equals d2 d1 does not almost equal d2

d1 is 0.2, d2 is 0.2 d1 != d2 d1 almost equals d2 d1 almost equals d2

clang 3.8

d1 is 0.200000003, d2 is 0.2000001073 d1 != d2 d1 almost equals d2 d1 does not almost equal d2

d1 is 0.2, d2 is 0.2 d1 != d2 d1 almost equals d2 d1 almost equals d2

MVS 2015

d1 is 0.200000003, d2 is 0.2000001073 d1 != d2 d1 almost equals d2 d1 does not almost equal d2

d1 is 0.2, d2 is 0.2 d1 != d2 d1 almost equals d2 d1 almost equals d2

/**
* @license This file is distributed under the MIT License.
* @author Denis Trofimov
**/
#include <cmath>
#include <limits>
#include <iomanip>
#include <iostream>
#include <type_traits>
#include <algorithm>
template<class T>
typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
almostEquals(T a, T b)
{
if(!std::isfinite(a) || !std::isfinite(b)) return false;
T maximum = std::max( { T{1.0}, std::fabs(a) , std::fabs(b) } );
return std::fabs(a - b) < std::numeric_limits<T>::epsilon() * maximum;
}
template<typename T>
typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
almost_equal(T x, T y, int ulp)
{
// the machine epsilon has to be scaled to the magnitude of the values used
// and multiplied by the desired precision in ULPs (units in the last place)
return std::abs(x-y) < std::numeric_limits<T>::epsilon() * std::abs(x+y) * ulp
// unless the result is subnormal
|| std::abs(x-y) < std::numeric_limits<T>::min();
}
template<typename T>
void printTest(T d1, T d2){
std::cout.precision(10);
std::cout << "d1 is " << d1 << ", d2 is " << d2 << "\n";
if(d1 == d2)
std::cout << "d1 == d2\n";
else
std::cout << "d1 != d2\n";
if(almostEquals(d1, d2))
std::cout << "d1 almost equals d2\n";
else
std::cout << "d1 does not almost equal d2\n";
if(almost_equal(d1, d2, 2))
std::cout << "d1 almost equals d2\n";
else
std::cout << "d1 does not almost equal d2\n";
}
int main()
{
float t1_d1 = 0.2;
float t1_d2 = 0.2000001;
printTest(t1_d1, t1_d2);
std::cout << std::endl;
double t2_d1 = 0.2;
double t2_d2 = 1 / std::sqrt(5) / std::sqrt(5);
printTest(t2_d1, t2_d2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment