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

Das Ergebnis ist zu verwenden:Problem versucht, die C qsort Funktion

-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

Es ist falsch, weil die Reihenfolge von -1 und -1.1 wird geändert. Ich glaube, es passiert, weil meine "vergleichen" -Funktion.

Wie kann ich das beheben?

Dank

+2

_qsort_ funktioniert gut. Ihr _call to qsort_ ist defekt. – aaronasterling

Antwort

2

Durch den Unterschied zu dem ganzzahligen Rundungs ​​verlieren Sie die Präzision.

EDIT:

die Funktion vergleichen Ändern zu

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

Edit für AndreyT: Ich glaube nicht, dass nur 1 oder -1 Rückkehr wird eine Endlosschleife oder falsche Reihenfolge führen (es wird Tausche einfach gleiche Werte aus, die es nicht benötigt haben).

Ein expliziter Fall für die Rückgabe 0 kostet eine zusätzliche Float-Kompatibilität, und sie sind selten gleich. Somit könnte die Vergleichbarkeit für die Gleichheit weggelassen werden, wenn die Kollisionsrate in den Eingangsdaten klein ist.

+1

Funktioniert nicht. Diese Funktion gibt für gleiche Werte "-1" zurück, was bedeutet, dass für gleich "a" und "b", die "a" mit "b" vergleichen, "a AnT

+2

Yor Bearbeitung änderte nichts, außer dass jetzt gleiche Werte immer '1' zurückgeben. Der Standard 'qsort' ist für einen Komparator ausgelegt, der eine dreiwertige Funktion ist. Es ist im Allgemeinen nicht möglich, sie auf eine Zwei-Werte-Funktion zu reduzieren, unabhängig davon, was Sie tun. Sie müssen '-1, 0, + 1' zurückgeben. – AnT

+1

Es ist nicht ungewöhnlich, dass eine Debug-Implementierung von 'qsort' die Korrektheit der Vergleichsfunktion überprüft. Wenn Ihre Vergleichsfunktion '1' für' (a, b) 'Vergleich liefert und gleichzeitig' 1' für '(b, a)' Vergleich zurückgibt, wird eine solche Debug 'qsort' Implementierung in der Regel sofort mit einer asserion abgebrochen Fehler. Die Nicht-Debug-Implementierung erzeugt einfach undefiniertes Verhalten. – AnT

31

Ihre Vergleichsfunktion ist kaputt. Es heißt zum Beispiel, dass -1.0 gleich (äquivalent) zu -1.1 ist, da (int) ((-1.0) - (-1.1)) Null ist. Mit anderen Worten, Sie selbst sagten qsort, dass die relative Reihenfolge von -1.0 und -1.1 keine Rolle spielt. Warum wundern Sie sich, dass in der resultierenden Reihenfolge diese Werte nicht sortiert sind?

Im Allgemeinen sollten Sie es vermeiden, numerische Werte durch Subtraktion von einander zu vergleichen. Es funktioniert einfach nicht. Bei Fließkommatypen kann es aus verschiedenen Gründen zu ungenauen Ergebnissen führen, von denen Sie gerade selbst beobachtet haben. Bei Integer-Typen kann es zu einem Überlauf kommen.

Das allgemeine Idiom zum Vergleichen zweier Zahlenwerte a und b für qsort sieht wie (a > b) - (a < b) aus. Erinnere dich daran und benutze es. In Ihrem Fall, dass

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

in C-Code wäre es durchaus Sinn machen könnte ein Makro

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

und es verwenden, statt formulierend die Vergleiche explizit zu definieren.

+2

+1 Es muss mehr Plus geben und das muss als Antwort akzeptiert werden. –

+0

'return (fa> fb) - (fa fb); 'kann schneller sein. YMMV. – chux

+0

@chux: Warum wäre es schneller? – AnT