如何比较长双打与qsort和NaN?

chu*_*ica 6 c qsort

如何长的双打比较qsort(),并就不是一个数

在排序可能包含非数字的数组时,我想将所有这些放在NAN已排序数组的一端.


qsort() 对比较功能施加了一些限制.

如果第一个参数被认为分别小于,等于或大于第二个参数,则该函数应返回小于,等于或大于零的整数.
C11dr§7.22.5.23

当相同的对象...不止一次传递给比较函数时,结果应该彼此一致.也就是说,因为qsort它们应该在数组上定义一个总排序,......同一个对象应始终以相同的方式与密钥进行比较.
§7.22.54

a > ba <= b或如果a不是数字或b不是数字时,则为false .所以a > b是不一样的!(a <= b),因为他们有相反的结果,如果他们中的一个是NaN.

如果比较函数使用return (a > b) - (a < b);,代码将返回0,如果一个或两个 a或是bNaN.数组不会按照需要排序,它会丢失总排序要求.

long double使用分类功能,如当这种方式是很重要的int isnan(real-floating x);int isfinite(real-floating x);.我知道isfinite( finite_long_double_more_than_DBL_MAX)可能会回归虚假.所以我担心isnan(some_long_double)发生什么意外的事情.


我试过以下.它显然按需要排序.

子问题:是否compare()足以按要求排序?任何建议的简化?如果没有 - 如何解决?(对于此任务,0.0L和-0.0L等值可以以任何方式排序)

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

int compare(const void *a, const void *b) {
  const long double *fa = (const long double *) a;
  const long double *fb = (const long double *) b;
  if (*fa > *fb) return 1;
  if (*fa < *fb) return -1;

  if (*fa == *fb) {
    //return -memcmp(fa, fb, sizeof *fa); if -0.0, 0.0 order important.
    return 0;
  }
  // At least one of *fa or *fb is NaN
  // is *fa a non-NaN?
  if (!isnan(*fa)) return -1;
  if (!isnan(*fb)) return 1;

  // both NaN
  return 0;
  // return -memcmp(fa, fb, tbd size); if NaN order important.
}

int main(void) {
  long double x[] = { 0.0L / 0.0, 0.0L / 0.0, 0.0, 1.0L / 0.0, -0.0, LDBL_MIN,
      LDBL_MAX, 42.0, -1.0L / 0.0, 867-5309, -0.0 };
  x[0] = -x[0];
  printf("unsorted: ");
  size_t n = sizeof x / sizeof x[0];
  for (size_t i = 0; i < n; i++) {
    printf("%.3Le,", x[i]);
  }
  printf("\nsorted: ");
  qsort(x, n, sizeof x[0], compare);
  for (size_t i = 0; i < n; i++) {
    printf("%.3Le,", x[i]);
  }
  puts("");
}
Run Code Online (Sandbox Code Playgroud)

产量

unsorted: nan,-nan,0.000e+00,inf,-0.000e+00,3.362e-4932,1.190e+4932,4.200e+01,-inf,-4.442e+03,-0.000e+00,
sorted: -inf,-4.442e+03,-0.000e+00,0.000e+00,-0.000e+00,3.362e-4932,4.200e+01,1.190e+4932,inf,nan,-nan,
Run Code Online (Sandbox Code Playgroud)

如果我知道比较功能是正确的,我会发布Code Review以获得改进的想法.然而,我没有足够的信心,代码可以正常地与那些讨厌的NaN一起工作.

usr*_*301 5

这只是对测试的简单重新排序,但NaN如果您愿意,它会使状态更加清晰.

int compare(const void *a, const void *b)
{
    const long double fa = *(const long double *) a;
    const long double fb = *(const long double *) b;

    if (isnan(fa))
    {
        if (isnan(fb))
        {
            return 0;
        }
        return 1;
    }
    if (isnan(fb))
    {
        return -1;
    }
    if (fa > fb) return 1;
    if (fa < fb) return -1;

    /* no more comparisons needed */
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

由于测试NaN位于顶部且没有NaN应该通过,底部的三条线可以安全地替换为您的

return (a > b) - (a < b);
Run Code Online (Sandbox Code Playgroud)

除了不同的讨论类型NaN(有点听起来像一个CPU内核有多少天使能舞),这应该是足够稳定你的目的,我不能看到这段代码的任何可能的问题.

对于Clang,既-ffast-math不会-fdenormal-fp-math=[ieee|preserve-sign|positive-zero]产生其他结果.也没有用gcc的 -ffast-math, -funsafe-math-optimizations甚至-ffinite-math-only(后者很可能是因为有比直没有其他操作比较NaN).

为了完整,我测试了两者std::numeric_limits<double>::signaling_NaN();std::numeric_limits<double>::quiet_NaN();(来自C++ <limits.h>) - 再次,排序顺序没有区别.