2 回答
TA贡献1824条经验 获得超6个赞
此行为是由于使用abs
,一个与 一起使用的函数int
,并向其传递double
参数引起的。sdouble
被隐式转换为int
,在比较它们之前截断小数部分。从本质上讲,这意味着您采用原始数字,去除符号,然后去除小数点右侧的所有内容并比较这些值。所以8.123
和-8.9
都转换为8
, 比较相等。由于减法的输入是相反的,因此排序是按幅度降序排列的。
您的cpp.sh
输出反映了这一点;所有大小在 8 和 9 之间的值首先出现,然后是 3-4s,然后是 2-3s、1-2s 和小于 1 的值。
如果您想修复此问题以实际按一般降序排序,则需要一个正确使用-friendly函数的double
fabs
比较函数,例如
int comp(const void *a, const void* b)
{ SensorIndex* x = (SensorIndex*)a;
SensorIndex* y = (SensorIndex*)b;
double diff = fabs(y->value) - fabs(x->value);
if (diff < 0.0) return -1;
return diff > 0;
}
更新:进一步阅读,看起来std::abs
from<cmath>
已经与double
s 一起工作了很长时间,但std::abs
for s 仅在 C++17 中double
添加到<cstdlib>
(整数函数所在的位置)。而且实施者总是把这些东西弄错,所以不同的编译器会随机表现不同。无论如何,这里给出的两个答案都是正确的;如果您没有包含并且您使用的是 C++17 之前的编译器,则您应该只能访问基于整数的版本(或from ),这将在比较之前截断每个值。即使您使用的是正确的,将减法的结果返回为abs
<cmath>
std::abs
::abs
math.h
std::abs
double
int
会丢弃 difference 的小数部分,使幅度差异小于的任何值1.0
看起来相等。更糟糕的是,根据执行的特定比较及其排序(因为并非所有值都相互比较),这种效果的后果可能会连锁,因为比较排序更改可能会使看起来等于,而反过来又会1.0
看起来等于1.6
,2.5
即使如果将它们相互比较,1.0
则被正确识别为小于;2.5
理论上,只要每个数字与其他数字的差值在 1.0 以内,比较的结果就好像它们彼此相等(病态情况是的,但肯定会发生较小的此类错误)。
关键是,弄清楚这段代码的真正意图的唯一方法是弄清楚它最初编译的确切编译器版本和 C++ 标准,并在那里进行测试。
TA贡献1788条经验 获得超4个赞
您的比较功能中存在错误。你返回 anint这意味着你失去了绝对差异小于 的元素值之间的区别!1
int comp(const void* a, const void* b)
{
SensorIndex* x = (SensorIndex*)a;
SensorIndex* y = (SensorIndex*)b;
// what about differences between 0.0 and 1.0?
return abs(y->value) - abs(x->value);
}
您可以这样修复它:
int comp(const void* a, const void* b)
{ SensorIndex* x = (SensorIndex*)a;
SensorIndex* y = (SensorIndex*)b;
if(std::abs(y->value) < std::abs(x->value))
return -1;
return 1;
}
一种更现代(也更安全)的方法是使用std::vectorand std::sort:
// use a vector for dynamic arrays
std::vector<SensorIndex> s_tmp;
for(int i = 0; i < 200; ++i) {
s_tmp.push_back({q[i], i});
}
// use std::sort
std::sort(std::begin(s_tmp), std::end(s_tmp), [](SensorIndex const& a, SensorIndex const& b){
return std::abs(b.value) < std::abs(a.value);
});
- 2 回答
- 0 关注
- 85 浏览
添加回答
举报