与浮点数相比使用 epsilon 会破坏严格的弱排序吗?
Does using epsilon in comparison of floating-point break strict-weak-ordering?
是否遵循 class 打破严格弱排序(与常规 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
- Transitivity of incomparability: For all
x
,y
,z
in S
, if x
is incomparable with y
(meaning that neither x < y
nor y < x
is true
) and if y
is incomparable with z
, then x
is incomparable with z
.
同样,来自https://en.cppreference.com/w/cpp/named_req/Compare
If equiv(a, b) == true and equiv(b, c) == true
, then 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
)
因此,class 打破了严格的弱排序。
正如 Jarod42 的 .
中所解释的那样,LessWithEpsilon
确实没有对所有双打的域强加严格的弱顺序
但是,在某些情况下,输入的值域有限,LessWithEpsilon
可以对其施加严格的弱顺序。特别是,如果输入由一组不相交的范围组成,其中每个范围的值彼此相等(在 epsilon 内)并且不等于所有其他范围(范围之间的距离大于 epsilon)。
如果您想知道考虑有限的输入域是否合理,请考虑 std::less
也不会对所有双精度域强加严格的弱顺序 - 必须排除 NaN。
至于编写比较函数时的意图,我建议一个可能的替代方案:转换输入,使每个值都四舍五入到最接近的 epslon 倍数。从技术上讲,这将使输入对建议的比较函数有效,但它也变得不必要,因为我们使用 std::less
.
会得到相同的结果
是否遵循 class 打破严格弱排序(与常规 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
- Transitivity of incomparability: For all
x
,y
,z
inS
, ifx
is incomparable withy
(meaning that neitherx < y
nory < x
istrue
) and ify
is incomparable withz
, thenx
is incomparable withz
.
同样,来自https://en.cppreference.com/w/cpp/named_req/Compare
If
equiv(a, b) == true and equiv(b, c) == true
, thenequiv(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
)
因此,class 打破了严格的弱排序。
正如 Jarod42 的
LessWithEpsilon
确实没有对所有双打的域强加严格的弱顺序
但是,在某些情况下,输入的值域有限,LessWithEpsilon
可以对其施加严格的弱顺序。特别是,如果输入由一组不相交的范围组成,其中每个范围的值彼此相等(在 epsilon 内)并且不等于所有其他范围(范围之间的距离大于 epsilon)。
如果您想知道考虑有限的输入域是否合理,请考虑 std::less
也不会对所有双精度域强加严格的弱顺序 - 必须排除 NaN。
至于编写比较函数时的意图,我建议一个可能的替代方案:转换输入,使每个值都四舍五入到最接近的 epslon 倍数。从技术上讲,这将使输入对建议的比较函数有效,但它也变得不必要,因为我们使用 std::less
.