Como comparar duplas longas com qsort e com relação ao NaN?
Como comparar duplas longas comqsort()
e em relação anão é um número?
Ao classificar uma matriz que pode conter números não, eu gostaria de colocar todas essasNAN
para uma extremidade da matriz classificada.
qsort()
impõe alguma restrição à função de comparação.
A função retornará um número inteiro menor que, igual a ou maior que zero se o primeiro argumento for considerado respectivamente menor que, igual a ou maior que o segundo.
C11dr §7.22.5.2 3
Quando os mesmos objetos ... são passados mais de uma vez para a função de comparação, os resultados devem ser consistentes entre si. Ou seja, paraqsort
eles devem definir umpedido total na matriz, ... o mesmo objeto deve sempre comparar da mesma maneira com a chave.
§7.22.5 4
a > b
é falso quandoa <= b
ou sea
não é um número ou seb
não é um número. assima > b
não é o mesmo que!(a <= b)
como eles têm resultados opostos se um deles é NaN.
Se a função comparar usarreturn (a > b) - (a < b);
, o código retornaria 0 se um ou ambosa
oub
são NaN. A matriz não seria classificada como desejada e perde apedido total requerimento.
olong double
Esse aspecto desse tipo é importante ao usar as funções de classificação comoint isnan(real-floating x);
ouint isfinite(real-floating x);
. eu seiisfinite( finite_long_double_more_than_DBL_MAX)
pode retornar falso. Então, eu tenho preocupações sobre o queisnan(some_long_double)
pode fazeralguma coisa inesperado.
Eu tentei o abaixo. Aparentemente, classifica como desejado.
Sub-pergunta: Écompare()
abaixo suficiente para classificar como desejado? Alguma simplificação recomendada? Se não - como consertar? (Para esta tarefa, não há problema em valores como 0,0L e -0,0L para classificar de qualquer maneira)
#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("");
}
Resultado
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,
Se eu soubesse que a função de comparação estava correta, publicaria uma revisão de código para obter idéias de melhoria. No entanto, não estou confiante o suficiente para que o código funcione corretamente com esses NaNs irritantes.