Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 若我为浮点数定义了一个自定义比较函数,那个么std::sort会正常工作吗?_C++_Sorting_Floating Point - Fatal编程技术网

C++ 若我为浮点数定义了一个自定义比较函数,那个么std::sort会正常工作吗?

C++ 若我为浮点数定义了一个自定义比较函数,那个么std::sort会正常工作吗?,c++,sorting,floating-point,C++,Sorting,Floating Point,对于浮点数的问题,我定义了浮点数的自定义比较函数: bool cmp(double a, double b) { if(abs(a - b) <= eps) return false; return a < b; } 我想把2和2.000000001看成是相同的,并期望结果是: (1,2), (2.000000001, 0), (2,1) 你为什么要费心做一个近似的比较呢?这毫无意义 只需严格按照实际值对数组进行排序 然后使用您的近似比较函数来确定您希望考虑哪些元

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

bool cmp(double a, double b)
{
    if(abs(a - b) <= eps) return false;
    return a < b;
}
我想把2和2.000000001看成是相同的,并期望结果是:

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

你为什么要费心做一个近似的比较呢?这毫无意义

只需严格按照实际值对数组进行排序

然后使用您的近似比较函数来确定您希望考虑哪些元素是相等的。< /P>


(英语中的等效词是臭名昭著的“几乎更好”。想想看。)

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

  • 我们定义了两个项目,
    a
    b
    ,如果
    ,则它们是等价的
    a===b
    )!cmp(a,b)&!cmp(b,a)
  • 等价是可传递的:
    a===b
    &&b==c=>
    a==c
正如您在问题中已经说过的,您的函数
cmp()
不满足这些条件,因此您不能在
std::sort()
中使用函数。不仅算法的结果是不可预测的,这是很糟糕的,除非你真的在寻找这种不可预测性(参见
随机化
):如果你有几个值彼此非常接近,以至于它们中的任何一个将
与某些值进行比较,而将
与其他值进行比较,该算法可能会进入一个无限循环


因此答案是否定的,您不能在
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;
}
bool cmp(双a双b)
{
常数双eps=0.0001;
INTA_exp;
双a_mant=frexp(a,&a_exp);//介于0.5和1.0之间
a_mant-=modf(a_mant,eps);//将a_mant四舍五入到0.00001
a=ldexp(a_mant,a_exp);//将a四舍五入到0.00001*10^a_exp
//b也一样
int b_exp;
双b_mant=frexp(b和b_exp);
b_mant-=modf(b_mant,每股收益);
b=ldexp(b_-mant,b_-exp);
//比较四舍五入的结果。
返回a

现在
cmp(a,b)==true
意味着
ab
两者都意味着
cmp(a,b)==false

我想对一对双精度进行排序。如果第一个相等,我将比较第二个。我认为对第一个键进行排序,然后对第二个键进行多次排序有点笨拙。@chyx:都一样,先按字典顺序对这些对进行排序,否则你永远不会有一个可靠的算法适用于所有情况。确定“等效”值是非常重要的,而且您不会回避单独和勤奋地处理该问题。它相当精致。将第一个值分组为等价组后,可以对第二个键进行排序。谢谢您的建议。我将修改我的代码。但我仍然很好奇
cmp
是否会导致排序失败。:-)@CHYX:即使是成对的,也可以对第一个值进行一次排序,然后决定要考虑什么,然后使用修改后的第一个值再次排序(现在等价值等于)和第二个值。或者,将所有值四舍五入到eps的最近倍数,然后进行排序,尽管我怀疑四舍五入并不能解决所有一个ulp输出问题。@chyx:where
a
b
是问题中的两倍吗?你可以用严格的IEEE模式来确保这一点,我认为你可以确信它是关于C++标准的。可能存在“松散”或“快速”模式,允许将
b
存储在超精密浮点寄存器中,而
a
存储在内存中。为了符合要求,我认为这种模式必须先将
b
四舍五入到
double
,然后再与
a
进行比较,但我打赌不会。因此,在不一致的编译器模式下,它可能会出错,但我怀疑排序时会出现超精度情况。正确使用“几乎相等”需要深入的浮点数学知识。它不能代替理解代码正在做什么。
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;
}