2010-10-07 16 views
9
#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; 
} 

El resultado es:problema al intentar utilizar la función C qsort

-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

Está mal porque el orden de -1 y -1.1 se cambia. Creo que está sucediendo porque mi función "comparar".

¿Cómo puedo solucionar esto?

Gracias

+2

_qsort_ funciona bien. Su llamada a qsort_ está rota. – aaronasterling

Respuesta

2

redondeando la diferencia en el número entero que pierden la precisión.

EDIT:

Modificar la función de comparación de

return (*(float*)a >= *(float*)b) ? 1 : -1;

Editar para AndreyT: No creo que la devolución sólo se 1 o -1 causará un bucle infinito o orden incorrecto (lo hará solo intercambia valores iguales que no lo requirieron).

Tener un caso explícito para regresar 0 tendrá un costo adicional compatation flotador, y que rara vez son iguales. Por lo tanto, la comparación de equalidad podría omitirse si la tasa de colisión en los datos de entrada es pequeña.

+1

No funciona. Esta función devolverá '-1' para valores iguales, lo que significa que para' a' y 'b' iguales que comparen' a' a 'b' dirá que' a AnT

+2

Yor edit no cambió nada, excepto que ahora los valores iguales siempre devolverán '1'. El 'qsort' estándar está diseñado para un comparador que es una función de tres valores. Generalmente no es posible reducirlo a una función de dos valores, independientemente de lo que haga. Tienes que devolver '-1, 0, + 1'. – AnT

+1

No es inusual que una implementación de depuración de 'qsort' compruebe la corrección de la función de comparación. Si su función de comparación devolverá '1' para la comparación' (a, b) 'y al mismo tiempo devolverá' 1' para la comparación '(b, a)', dicha implementación 'qsort' de depuración típicamente abortará inmediatamente con un asserion fracaso. La implementación sin errores simplemente producirá un comportamiento indefinido. – AnT

31

Su función de comparación se ha roto. Se dice, por ejemplo, que -1.0 es igual (equivalente) para -1.1, ya (int) ((-1.0) - (-1.1)) es cero. En otras palabras, tú mismo dijiste qsort que el orden relativo de -1.0 y -1.1 no importa. ¿Por qué te sorprende que en el ordenamiento resultante no se clasifiquen estos valores?

En general, se debe evitar la comparación de los valores numéricos restando uno del otro. Simplemente no funciona. Para los tipos de coma flotante puede producir resultados imprecisos por varias razones diferentes, una de las cuales acabas de observar. Para tipos enteros, podría desbordarse.

La expresión genérica para comparar dos valores numéricos a y b para qsort se ve como (a > b) - (a < b). Recordarlo y usarlo. En su caso sería

int compare (const void * a, const void * b) 
{ 
    float fa = *(const float*) a; 
    float fb = *(const float*) b; 
    return (fa > fb) - (fa < fb); 
} 

en código C podría tener sentido perfecto para definir una macro

#define COMPARE(a, b) (((a) > (b)) - ((a) < (b))) 

y usarlo en lugar de detallar las comparaciones de manera explícita.

+2

+1 Tiene que haber más más y esto debe aceptarse como la respuesta. –

+0

'return (fa> fb) - (fa fb); 'puede ser más rápido. YMMV. – chux

+0

@chux: ¿Por qué sería más rápido? – AnT

Cuestiones relacionadas