尝试使用 C qsort 函数时出现问题
#include <stdio.h>
#include <stdlib.h>
float values[] = { 4, 1, 10, 9, 2, 5, -1, -9, -2,10000,-0.05,-3,-1.1 };
int compare (const void * a, const void * b)
{
return ( (int) (*(float*)a - *(float*)b) );
}
int main ()
{
int i;
qsort (values, 13, sizeof(float), compare);
for (i = 0; i < 13; i++)
{
printf ("%f ",values[ i ]);
}
putchar('\n');
return 0;
}
结果是:
-9.000000 -3.000000 -2.000000 -1.000000 -1.100000 -0.050000 1.000000 2.000000 4.000000 5.000000 9.000000 10.000000 10000.000 000
错误,因为-1 和-1.1 的顺序改变了。 我相信这是因为我的“比较”功能而发生的。
我该如何解决这个问题?
谢谢
#include <stdio.h>
#include <stdlib.h>
float values[] = { 4, 1, 10, 9, 2, 5, -1, -9, -2,10000,-0.05,-3,-1.1 };
int compare (const void * a, const void * b)
{
return ( (int) (*(float*)a - *(float*)b) );
}
int main ()
{
int i;
qsort (values, 13, sizeof(float), compare);
for (i = 0; i < 13; i++)
{
printf ("%f ",values[ i ]);
}
putchar('\n');
return 0;
}
The result is:
-9.000000 -3.000000 -2.000000 -1.000000 -1.100000 -0.050000 1.000000 2.000000 4.000000 5.000000 9.000000 10.000000 10000.000000
It's wrong because the order of -1 and -1.1 is changed.
I believe it is happening because my "compare" function.
How can I fix this?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
要添加到 @AnT 的现有答案,您可以通过 SortChecker< 自动验证您的
qsort
回调/a>:此警告表示
compare
报告x < y,y< z
而不是x
z
对于某些输入。要进一步调试此问题,请运行并检查生成的代码转储。
To add to existing answer by @AnT, you can automatically verify your
qsort
callback via SortChecker:This warning says that
compare
reportsx < y, y < z
and notx < z
for some inputs. To further debug this issue, run withand examine generated codedump.
你的比较功能坏了。例如,它表示
-1.0
等于(等效)于-1.1
,因为(int) ((-1.0) - (-1.1))
为零。换句话说,您自己告诉qsort
-1.0
和-1.1
的相对顺序并不重要。为什么您会对结果排序中这些值未排序感到惊讶?一般来说,您应该避免通过将一个数值与另一个数值相减来比较数值。它就是行不通。对于浮点类型,它可能会由于多种不同的原因而产生不精确的结果,其中之一是您刚刚观察到的。对于整数类型,它可能会溢出。
用于比较
qsort
的两个数值a
和b
的通用习惯用法看起来为(a > b) - (a <; b)
。记住它并使用它。在您的情况下,在 C 代码中,定义宏
并使用它而不是显式地拼写比较可能是非常有意义的。
Your comparison function is broken. It says, for example, that
-1.0
is equal (equivalent) to-1.1
, since(int) ((-1.0) - (-1.1))
is zero. In other words, you yourself toldqsort
that the relative order of-1.0
and-1.1
does not matter. Why are you surprised that in the resultant ordering these values are not sorted?In general, you should avoid comparing numerical values by subtracting one from another. It just doesn't work. For floating-point types it might produce imprecise results for quite a few different reasons, one of which you just observed yourself. For integer types it might overflow.
The generic idiom for comparing two numerical values
a
andb
forqsort
looks as(a > b) - (a < b)
. Remember it and use it. In your case that would beIn C code it might make perfect sense to define a macro
and use it instead of spelling out the comparisons explicitly.
通过将差值四舍五入到整数,您会失去精度。
编辑:
将比较函数修改为
return (*(float*)a >= *(float*)b) ? 1 : -1;
为 AndreyT 编辑:我不认为仅返回
1
或-1
会导致无限循环或不正确的排序(它会只需交换不需要的等值)。明确返回
0
的情况将花费额外的浮点计算,并且它们很少相等。因此,如果输入数据中的冲突率很小,则可以省略相等性比较。By rounding the difference to the integer you lose the precision.
EDIT:
Modify the compare function to
return (*(float*)a >= *(float*)b) ? 1 : -1;
Edit for AndreyT: I don't think that returning only
1
or-1
will cause an infinite loop or incorrect ordering (it will just exchange equal values that didn't require it).Having an explicit case for returning
0
will cost an additional float compatation, and they are rarely equal. So, the comparation for equallity could be omitted if the collision rate in the input data is small.