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
,则它们是等价的(
)!cmp(a,b)&!cmp(b,a)a===b
- 等价是可传递的:
&&b==c=>a===b
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:wherea
和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;
}