#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.000000
这是错误的,因为-1和-1.1的顺序被改变了。 我相信它正在发生,因为我的“比较”功能。
我该如何解决这个问题?
由于
答案 0 :(得分:36)
您的比较功能已损坏。例如,它表示-1.0
与-1.1
相等(等效),因为(int) ((-1.0) - (-1.1))
为零。换句话说,您自己告诉qsort
-1.0
和-1.1
的相对顺序并不重要。为什么你感到惊讶的是,在结果排序中这些值没有排序?
通常,您应该避免通过相减数字来比较数值。它只是不起作用。对于浮点类型,由于很多不同的原因,它可能会产生不精确的结果,其中一个原因就是您自己观察到的。对于整数类型,它可能会溢出。
用于比较a
的两个数值b
和qsort
的通用惯用法看起来像(a > b) - (a < b)
。记住它并使用它。在您的情况下将是
int compare (const void * a, const void * b)
{
float fa = *(const float*) a;
float fb = *(const float*) b;
return (fa > fb) - (fa < fb);
}
在C代码中,定义宏
可能非常有意义#define COMPARE(a, b) (((a) > (b)) - ((a) < (b)))
并使用它而不是明确地拼写出比较。
答案 1 :(得分:1)
通过将差值四舍五入为整数,您将失去精度。
编辑:
将比较功能修改为
return (*(float*)a >= *(float*)b) ? 1 : -1;
为AndreyT编辑:我认为仅返回1
或-1
将导致无限循环或错误排序(它只会交换不需要它的相等值)。< / p>
有一个明确的返回0
的情况将花费额外的浮动比较,并且它们很少相等。因此,如果输入数据中的碰撞率很小,则可以省略对等式的比较。
答案 2 :(得分:0)
要通过@AnT添加到现有答案,您可以通过SortChecker自动验证qsort
回调:
$ LD_PRELOAD=$HOME/sortcheck-master/bin/libsortcheck.so ./a.out
a.out[7133]: qsort: comparison function is not transitive (comparison function 0x4005cd (/home/iuriig/a.out+0x4005cd), called from 0x400614 (/home/iuriig/a.out+0x400614), cmdline is "./a.out")
-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
此警告表示compare
报告x < y, y < z
而非x < z
报告某些输入。要进一步调试此问题,请使用
export SORTCHECK_OPTIONS=raise=1
并检查生成的codedump。