如果你关心的是整个容器的平等性,我会向你推荐::std::equal
算法。具体方法如下:
const double tolerance = 0.01;
bool equal = m1.size() == m2.size() &&
::std::equal(m1.begin(), m1.end(), m2.begin(),
[tolerance](const decltype(m1)::value_type &a,
const decltype(m2)::value_type) &b) {
return (a.first == b.first) &&
(::std::abs(a.second - b.second) < tolerance);
});
如果你在乎一个“小于”的关系,那么::std::lexicographical_compare
是你想要的。这需要C++ 11 lambda功能才能工作。
如果你真的想要的是以模糊的方式比较相等的数据值,我向你展示一些黑客(并且还需要一些C++ 11功能)fuzzy-double.cpp
。我禁用排序比较,因为这会诱使您将这些东西装入容器中,并且因为(2.0 == 2.1) && (2.1 == 2.2)
,但是(2.0 != 2.2)
,它们不适合此目的。
#include <cmath>
#include <iostream>
template <const double &tolerance>
class fuzzy_double {
public:
fuzzy_double(double x) : x_(x) {
static_assert(tolerance >= 0, "tolerance must be >= 0");
}
operator double() const { return x_; }
const fuzzy_double &operator =(double x) { x_ = x; }
bool equals(const fuzzy_double &b) const {
return ::std::abs(x_ - b.x_) <= tolerance;
}
// This cannot be used as the basis of a 'less than' comparison operator for
// the purposes of other algorithms because it's possible for a transitive
// equality relationship to exit that equates all fuzzy_double's to
// eachother. There is no strict ordering that makes sense.
bool fuzzy_less(const fuzzy_double &b) const {
return (b.x_ - x_) > tolerance;
}
private:
double x_;
};
template <const double &tolerance>
bool operator ==(const fuzzy_double<tolerance> &a,
const fuzzy_double<tolerance> &b)
{
return a.equals(b);
}
template <const double &tolerance>
bool operator !=(const fuzzy_double<tolerance> &a,
const fuzzy_double<tolerance> &b)
{
return !a.equals(b);
}
template <const double &tolerance>
bool operator <(const fuzzy_double<tolerance> &a,
const fuzzy_double<tolerance> &b)
{
// tolerance < 0 should be an impossible condition and always be false, but
// it's dependent on the template parameter and so only evaluated when the
// template is instantiated.
static_assert(tolerance < 0, "fuzzy_doubles cannot be ordered.");
return false;
}
template <const double &tolerance>
bool operator >=(const fuzzy_double<tolerance> &a,
const fuzzy_double<tolerance> &b)
{
// tolerance < 0 should be an impossible condition and always be false, but
// it's dependent on the template parameter and so only evaluated when the
// template is instantiated.
static_assert(tolerance < 0, "fuzzy_doubles cannot be ordered.");
return false;
}
template <const double &tolerance>
bool operator >(const fuzzy_double<tolerance> &a,
const fuzzy_double<tolerance> &b)
{
// tolerance < 0 should be an impossible condition and always be false, but
// it's dependent on the template parameter and so only evaluated when the
// template is instantiated.
static_assert(tolerance < 0, "fuzzy_doubles cannot be ordered.");
return false;
}
template <const double &tolerance>
bool operator <=(const fuzzy_double<tolerance> &a,
const fuzzy_double<tolerance> &b)
{
// tolerance < 0 should be an impossible condition and always be false, but
// it's dependent on the template parameter and so only evaluated when the
// template is instantiated.
static_assert(tolerance < 0, "fuzzy_doubles cannot be ordered.");
return false;
}
extern constexpr double ten_e_minus_2 = 0.01;
int main()
{
fuzzy_double<ten_e_minus_2> a(3);
fuzzy_double<ten_e_minus_2> b(3.009);
fuzzy_double<ten_e_minus_2> c(2.991);
fuzzy_double<ten_e_minus_2> d(3.011);
fuzzy_double<ten_e_minus_2> e(2.989);
using ::std::cout;
cout << "a == a: " << (a == a) << '\n';
cout << "a == b: " << (a == b) << '\n';
cout << "a == c: " << (a == c) << '\n';
cout << "a == d: " << (a == d) << '\n';
cout << "a == e: " << (a == e) << '\n';
return 0;
}
C++ 11不允许double
,甚至没有const
一个,是一个模板参数。 OTOH允许指针和引用具有外部链接的对象作为模板参数。因此,如果您将容差声明为extern constexpr double
,则可以使用指定容差作为模板参数。
你关心一个键是否小于另一个?还是只是平等? – Omnifarious 2012-03-29 18:37:19
你不能以这样一种方式定义这样的比较,即在不使所有*值等于的情况下给你一个严格的弱排序:你想要20等于20.1,等于20.2,...,等于99.9,等于100.0。排序是传递的! – 2012-03-29 18:59:42
@KerrekSB:哦,你是对的!如果以这种方式使用数据值,排序将具有配置。所以是的,真正的*小于*关系是不可能的。我需要修改我的修改答案。 – Omnifarious 2012-03-29 19:31:41