问题描述
以下课程是否打破了严格弱序(与常规 std::less
相比(因此忽略边缘情况值,例如 Nan))
struct LessWithEpsilon
{
static constexpr double epsilon = some_value;
bool operator() (double lhs,double rhs) const
{
return lhs + epsilon < rhs;
}
};
LessWithEpsilon lessEps{};
解决方法
来自https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings
- 不可比性的传递性:对于
x
中的所有y
、z
、S
,如果x
与y
不可比(意味着x < y
和y < x
都不是true
),如果y
与z
不可比,那么x
与z
不可比。
同样,来自https://en.cppreference.com/w/cpp/named_req/Compare
如果equiv(a,b) == true and equiv(b,c) == true
,则equiv(a,c) == true
有了 {x,y,z} = {0,epsilon,2 * epsilon}
,这条规则就被打破了:
-
!lessEps(x,y) && !lessEps(y,x) && !lessEps(y,z) && !lessEps(z,y)
但是lessEps(x,z)
。 -
equiv(x,y) == true and equiv(y,z) == true
但equiv(x,z) == false
(如x + epsilon < z
)
因此,该类打破了严格弱序。
,正如 Jarod42 的 answer 所解释的那样,LessWithEpsilon
确实没有对所有双精度域强加严格的弱顺序。
但是,在某些情况下,输入的值域有限,LessWithEpsilon
可以对其施加严格的弱顺序。特别是,如果输入由一组不相交的范围组成,其中每个范围的值彼此相等(在 epsilon 内)并且不等于所有其他范围(范围之间的距离大于 epsilon)。
如果您想知道考虑有限输入域是否合理,请考虑 std::less
也不会对所有双精度域施加严格的弱顺序 - 必须排除 NaN。
至于编写比较函数时的意图,我提出了一个可能的替代方案:转换输入,使每个值四舍五入到最接近的 epslon 倍数。从技术上讲,这将使输入对建议的比较函数有效,但也使其变得不必要,因为我们使用 std::less
会得到相同的结果。