4

If compare between float, I think cannot just use equal ==, need to check if abs(a-b) < epsilon. So when float type value is used as a key, can we use equal_range function?

such as:

std::multimap<float, string>  ds;
ds.insert(make_pair(2.0, string("a")));
ds.insert(make_pair(2.0, string("b")));
ds.insert(make_pair(3.0, string("d")));
ds.equal_range(2.0)
yewei
  • 241
  • 2
  • 9
  • the problem of `float` is like what you said, there is inaccuracy, so if you want to use `float` as key, make sure all your calculations are done with `float`; And, append `f` behind your constants, like `2.0f` – Marson Mao Aug 12 '15 at 08:35

4 Answers4

4

std::multimap::equal_range is not actually calculated using operator== at all. It is calculated using < AND > only. It is actually two iterators, the first being the std::multimap::lower_bound (first element not less than the given key) and the second being the std::multimap::upper_bound (first element greater than the given key).

So it is quite safe to use with floats and doubles.

Galik
  • 47,303
  • 4
  • 80
  • 117
0

Just test it and you'll see it obviously works.

#include    <map>
#include    <string>
#include    <iostream>

int main()
{
    std::multimap<float, std::string>  ds;
    ds.emplace(2.0f, std::string("a"));
    ds.emplace(2.0f, std::string("b"));
    ds.emplace(3.0f, std::string("d"));

    auto r = ds.equal_range(2.0f);
    for ( auto it = r.first; it != r.second; ++it )
        std::cout << it->second << std::endl;
}

Output:

a
b
  • 4
    In C++, "it obviously works" is the sentence that predates weeks of debugging to know why it suddenly doesn't. – Quentin Aug 12 '15 at 09:14
-1

You can define your own less-operator for float. See the following example.

// http://www.cplusplus.com/reference/map/multimap/

#include <map>
#include <cassert>
#include <iostream>
#include <algorithm>

class CApproxFloatLess {
    double m_eps;
public:
    CApproxFloatLess(float eps) :
    m_eps(eps)
    {
        assert(eps >= 0);
    }

    bool operator () (float x, float y) const {
        return x + m_eps*(1+std::abs(x)) < y;
    }
};

template <class It>
void info(float x, It& it) {
    std::cout << "Found pair (" << it->first << ", " << it->second << ") for " << x << ".\n";
}

int main() {
    typedef std::multimap<float,std::string,CApproxFloatLess> MyMap;
    MyMap ds(CApproxFloatLess(1e-3));

    ds.insert(make_pair(2.0, std::string("a")));
    ds.insert(make_pair(2.0, std::string("b")));
    ds.insert(make_pair(3.0, std::string("d")));


    float x=2.001;
    MyMap::iterator it=ds.find(x);
    if( it != ds.end() )
        info(x,it);

    x=1.999;
    it=ds.find(x);
    if( it != ds.end() )
        info(x,it);

    x=2.01;
    it=ds.find(x);
    if( it != ds.end() )
        info(x,it);

    x=3.001;
    it=ds.find(x);
    if( it != ds.end() )
        info(x,it);

    return 0;
}

The output of this program is:

Found pair (2, a) for 2.001.
Found pair (2, a) for 1.999.
Found pair (3, d) for 3.001.
Tobias
  • 5,038
  • 1
  • 18
  • 39
  • This is UB. Your comparison is not a valid strict weak ordering. – T.C. Aug 12 '15 at 07:27
  • @T.C. The actual comment should be: Don't use `float` as keytype. It is true that `float` is almost a type that has a strict weak ordering (disregarding difficulties with NaN). But, as soon as you use real calculation you cannot rely on this ordering anymore. Besides, even if the code does not fully satisfy the conditions for `std::map` I cannot think of a sensible implementation that would not give the same answer. – Tobias Aug 12 '15 at 10:17
-2

Who says you cannot use == to compare two floats? == works perfectly fine for floats; it will return true if they are equal and false if they are different. (There is some odd things about NaN's and negative zeroes, but that's not covered by a range check).

Obviously if you search for a value that isn't equal using == to any value in the multi map, it won't be found. And if you add two values that are as close to each other as possible, they will both be added.

gnasher729
  • 51,477
  • 5
  • 75
  • 98