【问题标题】:Problems when i'm using qsort for double当我使用 qsort for double 时出现问题
【发布时间】:2013-10-08 04:10:40
【问题描述】:

我的英文很差,如有错误请见谅。谢谢!

当我使用 qsort 对该结构进行排序时遇到了这个问题:

    typedef struct 
{
    double cost,earn;
}ac;

我想这样排序:

int cmp(const void *a,const void *b)
{
    ac this_a=*(ac*)a;
    ac this_b=*(ac*)b;
    return (this_b.earn/this_b.cost-this_a.earn/this_a.cost)>0.0;
}

但它没有用。当我改成这个时,它起作用了:

int cmp(const void *a,const void *b)
{
    ac this_a=*(ac*)a;
    ac this_b=*(ac*)b;
    return (this_a.cost*this_b.earn-this_a.earn*this_b.cost);
}

为什么会这样?这两个功能有什么不同吗?或者可能代码的另一部分是错误的?

【问题讨论】:

  • 删除第一个示例中的>0.0,它会运行得很好
  • @Lưu Vĩnh Phúc:两者之间的区别不仅限于> 0.0。在第二种情况下对公式所做的更改显然是为了避免“被零除”问题。显然,这也是一个问题。因此,在第一种情况下删除 >0.0 显然是不够的。
  • @AndreyT:是的,你是对的,第二个不仅能解决问题,还能提高性能
  • @Lưu Vĩnh Phúc:性能可能会更好,但第二个仍然坏:它存在溢出问题。
  • 谢谢大家。实际上,输入的数量很小,因此不会出现溢出问题。

标签: c qsort


【解决方案1】:

比较函数必须返回一个小于零、等于零或大于零的整数,具体取决于您希望这两个项目如何排序。

在您的第一个示例中,您返回 > 操作的结果。这是 0 或 1。

【讨论】:

  • 谢谢。因此,当我想对分数进行排序时,我不应该直接对其进行排序,而是将其更改为减法。 (我的英语太差了……)
  • 第二个版本也有问题:当减法的结果为非零但幅度小于1时,它会错误返回零,并且在其他情况下,转换为int可能会溢出.
【解决方案2】:

您可以很容易地看到,这两个函数之间是有区别的。第一个在return 语句中的表达式末尾包含> 0.0。 (另外,第一个使用除法,第二个使用乘法。但是,如果值是非负的,则应用于公式的转换实际上执行等效比较,而不会遭受被零除的危险。)

请注意,这两种实现都不好。正如您已经注意到的,第一个甚至没有远程执行qsort 的三态比较函数应该执行的操作。只要double 值相对较小,第二个就可以正常工作。但是随着这些值变大,从doubleint 的转换可能会开始溢出,从而导致未定义的行为。

因此,永远不要使用直接减法来生成三态比较结果(可能除了小于int 的类型)。如果您需要比较两个值,例如 ab,请使用 return (a > b) - (a < b) 成语。这就是你的情况

double lhs = this_a.cost * this_b.earn;
double rhs = this_a.earn * this_b.cost;
return (lhs > rhs) - (lhs < rhs);

【讨论】:

    【解决方案3】:

    第一个函数只会返回 0 或 1。

    第二个函数将返回“负数”、0 或“正数”,这可能是您想要表示的“小于”、“等于”和“大于”

    【讨论】:

      猜你喜欢
      • 2011-04-22
      • 2021-09-29
      • 2021-02-03
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      • 2018-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多