如果我为浮点数定义了自定义比较函数,std::sort 会正常工作吗?

Will std::sort work correctly if I defined a custom compare function for floating number?

本文关键字:常工作 sort 工作 std 定义 浮点数 自定义 函数 比较 如果      更新时间:2023-10-16

对于浮点精度的问题,我为浮点数定义了自定义比较函数:

bool cmp(double a, double b)
{
    if(abs(a - b) <= eps) return false;
    return a < b;
}

然后我对一些浮点数数组调用排序。我听说一些不好的比较函数会导致排序分段错误。我只是想知道cmp可以正常工作吗?一方面,cmp满足关联规则。但另一方面,cmp(x - eps, x) == false&&cmp(x, x + eps) == false并不意味着cmp(x - eps, x + eps) == false

我没有直接对浮点数使用排序,因为我想排序的是pair<double, double>.例如:

(1,2), (2,1), (2.000000001, 0)

我想将 2 和 2.000000001 视为相同,并期望结果为:

(1,2), (2.000000001, 0), (2,1)

>std::sort需要一个定义严格弱排序的比较器。这意味着,除其他事项外,必须满足以下条件:

  • 我们定义两个项目,ab,如果!cmp(a, b) && !cmp(b, a),则等a === b
  • 等价是传递的:a === b&&b === c=> a === c

正如您在问题中已经说过的,您的函数cmp()不满足这些条件,因此您无法在 std::sort() 中使用您的函数。不仅算法的结果是不可预测的,这很糟糕,除非你真的在寻找这种不可预测性(参见)。 randomize ):如果有几个彼此非常接近的值,使得它们中的任何一个true与某些值进行比较,但与其他一些值false,则算法可能会进入无限循环。

所以答案是否定的,你不能在std::sort()中使用你的函数cmp(),除非你想冒着程序冻结的风险。

你为什么要费心做一个近似的小于比较?这是没有道理的。

只需严格按实际值对数组进行排序即可。

然后使用近似比较函数来确定您希望认为哪些元素相等。

(英语中的等价物是臭名昭著的"几乎更好"。想一想。

可以为浮点数定义一个比较函数,对相似的值进行分组。您可以通过四舍五入来实现:

bool cmp(double a, double b)
{
    const double eps = 0.0001;
    int a_exp;
    double a_mant = frexp(a, &a_exp); // Between 0.5 and 1.0
    a_mant -= modf(a_mant, eps); // Round a_mant to 0.00001
    a = ldexp(a_mant, a_exp); // Round a to 0.00001 * 10^a_exp
    // and the same for b
    int b_exp;
    double b_mant = frexp(b, &b_exp); 
    b_mant -= modf(b_mant, eps);  
    b = ldexp(b_mant, b_exp);
    // Compare rounded results.
    return a < b;
}

现在cmp(a,b)==true暗示a<ba==ba>b都暗示cmp(a,b)==false