jeudi 23 avril 2015

C++ floating point comparison questions

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 cstdint manually via template specialization?
  • is the intss_t size, 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