I made yet another C++ floating point number comparison function:
#include <cmath>
#include <cstdlib>
#include <type_traits>
#include <boost/integer.hpp>
template <typename D>
bool almost_equal(D rhs, D lhs, int tolerance) {
static_assert(std::is_floating_point<D>::value, "template D must be a floating point type");
if (std::isnan(rhs) or std::isnan(lhs))
return false;
if (rhs == lhs) //includes both zeros or both same sign infinity
return true;
//intss_t same size int
using intss_t = typename boost::int_t<sizeof(D) * std::numeric_limits<unsigned char>::digits>::exact;
const int nbits { std::numeric_limits<intss_t>::digits };
const intss_t first_bit { intss_t{1} << (nbits - 1) };
union readbits {
D d;
intss_t i;
};
readbits brhs {};
readbits blhs {};
brhs.d = rhs;
blhs.d = lhs;
intss_t irhs { brhs.i };
intss_t ilhs { blhs.i };
if (irhs < 0) irhs = first_bit - irhs;
if (ilhs < 0) ilhs = first_bit - ilhs;
return std::abs(irhs - ilhs) <= tolerance;
}
There nothing new here, the idea is stating that two floats are equal enough if there are at most tolerance numbers that can be represented between the two. I made few tests and it seems to work. tolerance is meant to be a positive, but somewhat small number like 8.
However I have few questions:
- is it correct? (obviously nothing make sense if it is wrong)
- is there any testsuite I can use to see?
- there is standard (C++11) way to get the integer by size without using boost or mapping bit lengths to
cstdintmanually via template specialization? - is the
intss_tsize, by standard, of same length of the floating type passed? - the union trick is really a standard compliant to see the bits of a float? (assuming int and float are of the same size)
Aucun commentaire:
Enregistrer un commentaire