我正在将C++
代码转换为Go
,但在理解此比较功能时遇到困难:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
using namespace std;
typedef struct SensorIndex
{ double value;
int index;
} SensorIndex;
int comp(const void *a, const void* b)
{ SensorIndex* x = (SensorIndex*)a;
SensorIndex* y = (SensorIndex*)b;
return abs(y->value) - abs(x->value);
}
int main(int argc , char *argv[])
{
SensorIndex *s_tmp;
s_tmp = (SensorIndex *)malloc(sizeof(SensorIndex)*200);
double q[200] = {8.48359,8.41851,-2.53585,1.69949,0.00358129,-3.19341,3.29215,2.68201,-0.443549,-0.140532,1.64661,-1.84908,0.643066,1.53472,2.63785,-0.754417,0.431077,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256,-0.123256};
for( int i=0; i < 200; ++i ) {
s_tmp[i].value = q[i];
s_tmp[i].index = i;
}
qsort(s_tmp, 200, sizeof(SensorIndex), comp);
for( int i=0; i<200; i++)
{
cout << s_tmp[i].index << " " << s_tmp[i].value << endl;
}
}
我希望“ comp”功能可以允许从最高(绝对)值到次要值的排序,但是在我的环境(gcc 32位)中,结果是:
1 8.41851
0 8.48359
2 -2.53585
3 1.69949
11 -1.84908
5 -3.19341
6 3.29215
7 2.68201
10 1.64661
14 2.63785
12 0.643066
13 1.53472
4 0.00358129
9 -0.140532
8 -0.443549
15 -0.754417
16 0.431077
17 -0.123256
18 -0.123256
19 -0.123256
20 -0.123256
...
此外,令我感到奇怪的是,通过使用在线服务执行相同的代码,我得到了不同的值(cpp.sh,C ++ 98):
0 8.48359
1 8.41851
5 -3.19341
6 3.29215
2 -2.53585
7 2.68201
14 2.63785
3 1.69949
10 1.64661
11 -1.84908
13 1.53472
4 0.00358129
8 -0.443549
9 -0.140532
12 0.643066
15 -0.754417
16 0.431077
17 -0.123256
18 -0.123256
19 -0.123256
20 -0.123256
...
有帮助吗?
答案 0 :(得分:2)
您的比较功能中有一个错误。返回int
意味着您失去了绝对差小于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::vector
和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);
});
答案 1 :(得分:2)
此行为是由于使用abs
(一种与int
一起使用的函数)并将其传递给double
参数引起的。 double
被隐式转换为int
,在比较它们之前会截断小数部分。本质上,这意味着您要获取原始数字,去掉符号,然后去掉小数点右边的所有内容并比较这些值。因此8.123
和-8.9
都被转换为8
,并且比较相等。由于输入是反向进行减法运算,因此按大小顺序降序。
您的cpp.sh
输出反映了这一点;所有大小在8到9之间的值都将首先出现,然后是3-4s,然后是2-3s,1-2s和少于1个值。
如果您想解决此问题,使其实际上通常按降序排序,则需要一个比较函数,该函数应正确使用the double
-friendly fabs
function,例如
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
中的<cmath>
与double
s已有很长时间了,但是std::abs
在C ++ 17中,仅double
中的<cstdlib>
被添加到了abs
(整数<cmath>
函数所在的位置)中。 And the implementers got this stuff wrong all the time, so different compilers would behave differently at random。无论如何,这里给出的答案都是正确的。如果您尚未包括std::abs
,并且您使用的是C ++ 17之前的编译器,则应该仅可以访问基于整数的::abs
(或{{ math.h
中的1}}),它将在比较之前截断每个值。即使您使用正确的std::abs
,returning the result of double
subtraction as an int
would drop fractional components of the difference,也可以使幅度差小于1.0
的任何值都相等。更糟糕的是,根据执行的特定比较及其顺序(因为并非所有值都相互比较),这种影响的结果可能会连锁,因为比较顺序更改可能使1.0
看起来等于1.6
即使2.5
彼此比较时,即使1.0
可以正确地识别为小于2.5
,也将看起来等于r2
;从理论上讲,只要每个数字都在其他数字的1.0以内,则比较的结果就好像它们彼此相等(病理情况是,但是肯定会发生较小的错误)。
要点是,弄清楚此代码的 real 意图的唯一方法是弄清楚其最初在其下编译的确切的编译器版本和C ++标准,并在那里进行测试。