为什么stdlib中的qsort不能处理双精度值?[C]

4

我写了一个简单的程序来整理我的数组。问题是,该代码只适用于int值,而我需要我的数组具有double元素... 有什么帮助吗?

#include <stdio.h>
#include <stdlib.h>

double values[] = { 88, 56, 100, 2, 25 };

int cmpfunc (const void * a, const void * b)
{
    return ( *(int*)a - *(int*)b );
}

int main()
{
    int n;

    printf("Before sorting the list is: \n");
    for( n = 0 ; n < 5; n++ )
    {
        printf("%.2f ", values[n]);
    }

    printf("\n\n");

    qsort(values, 5, sizeof(double), cmpfunc);

    printf("\nAfter sorting the list is: \n");
    for( n = 0 ; n < 5; n++ )
    {
        printf("%.2f ", values[n]);
    }

    printf("\n\n");

    return(0);
}

工作代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

double values[] = { 88, 56, 100, 2, 25 };

int compare (const void * a, const void * b)
{
    if (*(double*)a > *(double*)b) return 1;
    else if (*(double*)a < *(double*)b) return -1;
    else return 0;
}

int main()
{
    int n;

    printf("Before sorting the list is: \n");
    for( n = 0 ; n < 5; n++ )
    {
        printf("%.2f ", values[n]);
    }

    printf("\n\n");

    qsort(values, 5, sizeof(double), compare);

    printf("\nAfter sorting the list is: \n");
    for( n = 0 ; n < 5; n++ )
    {
        printf("%.2f ", values[n]);
    }

    printf("\n\n");

    return(0);
}

1
cmpfnc 正在将类型转换为 int* - Roger Rowland
如果您有双精度浮点数,为什么在比较函数中要强制转换为int*? - Oliver Charlesworth
你不能简单地说“这些是整数”-它们是双精度浮点数。尝试使用sgn:返回(sgn((double)a - (double)b)); - Rob
@haccks 为什么你需要 cmpfunc 的参数? - P0W
@haccks cmpfunc 是用于 qsort 的比较函数,我不知道你在说什么。 - P0W
3个回答

10

你想要对双精度浮点数进行排序,但是你将它们视为整型比较... 试试这个比较函数:

int cmpfunc (const void * a, const void * b)
{
  if (*(double*)a > *(double*)b)
    return 1;
  else if (*(double*)a < *(double*)b)
    return -1;
  else
    return 0;  
}

2

你是否错过了double*转换?:

同时修复评论中的一个问题。

int cmpfunc (const void * a, const void * b)
{
  return (*(double*)a > *(double*)b) ? 1 : (*(double*)a < *(double*)b) ? -1:0 ;
}

2
那么对于超出int范围的double呢(即使它们不在这里)? - Rob

1
您的比较函数是针对int而不是double的:
int cmpfunc (const void * a, const void * b)
{
    return ( *(int*)a - *(int*)b );
}

请注意,比较浮点数与比较整数值不同。由于浮点精度的原因,仅将 int * 更改为 double * 是不够的,您应该使用一个 epsilon 常量进行比较。

http://c-faq.com/fp/fpequal.html

编辑:我划掉了上面的段落,因为它与排序无关,请参阅评论部分。 我不删除我的答案以保留评论可见。


2
为什么你需要一个 epsilon? - Oliver Charlesworth
@OliCharlesworth 如果你在浮点数组中只使用字面值,那就没问题了,但如果你的数组元素是某些计算的结果,那么可能会出问题。 - ouah
但这是一个排序,而不是相等比较。 - Oliver Charlesworth
4
@ouah: 不,绝对不行。使用公差来比较浮点数,无论是为了相等性还是不等性,应该仅限于特定应用情况下。在库程序中不应该这样做,因为没有一般的标准可以确定何时相等或不等时产生误差。实际上,潜在的问题并不在于相等性。而是由于输入错误无法计算出任何函数。这个问题会因为函数不连续或者导数巨大而变得更加严重,但是对于所有函数都存在。 - Eric Postpischil
1
@ouah:在比较函数中没有容差的排序会生成一个有序数字列表。而带有容差的排序通常不会这样做。因此,使用容差是错误的。 - Eric Postpischil
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接