排序比较。

我正在将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);

    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

...

有什么帮助吗?


猛跑小猪
浏览 86回答 2
2回答

慕妹3242003

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

尚方宝剑之说

您的比较功能中存在错误。你返回 anint这意味着你失去了绝对差异小于 的元素值之间的区别!1int comp(const void* a, const void* b){&nbsp; &nbsp; SensorIndex* x = (SensorIndex*)a;&nbsp; &nbsp; SensorIndex* y = (SensorIndex*)b;&nbsp; &nbsp; // what about differences between 0.0 and 1.0?&nbsp; &nbsp; return abs(y->value) - abs(x->value);&nbsp;}您可以这样修复它:int comp(const void* a, const void* b){&nbsp; &nbsp;SensorIndex* x = (SensorIndex*)a;&nbsp; &nbsp; SensorIndex* y = (SensorIndex*)b;&nbsp; &nbsp; if(std::abs(y->value) < std::abs(x->value))&nbsp; &nbsp; &nbsp; &nbsp; return -1;&nbsp; &nbsp; return 1;}一种更现代(也更安全)的方法是使用std::vectorand std::sort:// use a vector for dynamic arraysstd::vector<SensorIndex> s_tmp;for(int i = 0; i < 200; ++i) {&nbsp; &nbsp; s_tmp.push_back({q[i], i});}// use std::sortstd::sort(std::begin(s_tmp), std::end(s_tmp), [](SensorIndex const& a, SensorIndex const& b){&nbsp; &nbsp; return std::abs(b.value) < std::abs(a.value);});
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go