2010-10-07 10 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; 
} 

Il risultato è:problema cercando di utilizzare la funzione 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

È sbagliato perché l'ordine di -1 e -1.1 è cambiato. Credo che stia accadendo perché la mia funzione "confronta".

Come posso risolvere questo problema?

Grazie

+2

_qsort_ funziona correttamente. Il tuo _call su qsort_ è rotto. – aaronasterling

risposta

2

arrotondando la differenza al numero intero si perde la precisione.

EDIT:

Modificare la funzione di confronto per

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

Edit per AndreyT: Non credo che il ritorno solo 1 o -1 causerà un ciclo infinito o ordinare errato (lo farà basta scambiare valori uguali che non lo richiedevano).

Avere un caso esplicito per la restituzione di 0 costerà una ulteriore compatibilità di tipo float e raramente sono uguali. Quindi, il confronto per l'equità potrebbe essere omesso se il tasso di collisione nei dati di input è piccolo.

+1

Non funziona. Questa funzione restituirà '-1' per valori uguali, il che significa che per un uguale' a' e 'b' il confronto di' a' a 'b' dirà che' a AnT

+2

La modifica non ha modificato nulla, tranne che ora i valori uguali restituiscono sempre '1'. Lo standard 'qsort' è progettato per un comparatore che è una funzione tri-valore. Generalmente non è possibile ridurlo a una funzione a due valori, indipendentemente da ciò che si fa. Devi restituire '-1, 0, + 1'. – AnT

+1

Non è insolito per un'implementazione di debug di 'qsort' per verificare la correttezza della funzione di confronto. Se la funzione di confronto restituisce '1' per il confronto' (a, b) 'e allo stesso tempo restituisce' 1' per '(b, a)' confronto, tale implementazione di debug 'qsort' tipicamente interromperà immediatamente con un'asserzione fallimento. L'implementazione non di debug produrrà semplicemente un comportamento non definito. – AnT

31

La funzione di confronto è interrotta. Ad esempio, si dice che -1.0 è uguale (equivalente) a -1.1, poiché (int) ((-1.0) - (-1.1)) è zero. In altre parole, tu stesso hai detto a qsort che l'ordine relativo di -1.0 e -1.1 non ha importanza. Perché sei sorpreso che nell'ordinamento risultante questi valori non siano ordinati?

In generale, si dovrebbe evitare di confrontare i valori numerici sottraendone uno da un altro. Semplicemente non funziona. Per i tipi a virgola mobile, potrebbe produrre risultati imprecisi per diversi motivi diversi, uno dei quali si è appena osservato. Per i tipi di interi potrebbe overflow.

L'idioma generico per il confronto di due valori numerici a e per qsort si presenta come (a > b) - (a < b). Ricordalo e usalo. Nel tuo caso, che sarebbe

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

Nel codice C potrebbe avere perfettamente senso per definire una macro

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

e utilizzarlo al posto di ortografia le comparazioni in modo esplicito.

+2

+1 Ci devono essere più plus e questo deve essere accettato come risposta. –

+0

'return (fa> fb) - (fa fb); 'potrebbe essere più veloce. YMMV. – chux

+0

@chux: Perché dovrebbe essere più veloce? – AnT

Problemi correlati