Ist ein relationaler Vergleich zwischen int und float in C direkt möglich?

7

Ich verwende Visual Studio 6 mit altem Zeitcode, der in c geschrieben ist. Ich habe ein Problem gefunden, bei dem der Code so aussieht.

%Vor%

ist das ein gültiger Vergleich? Ist es zur Laufzeit möglich, dass die Zuweisung für den Float 3.0000001 ist und dies fehlschlagen würde?

    
quelle

11 Antworten

1

Nun, ich denke, Sie werden nicht allzu überrascht sein zu hören, dass der Vergleich von Floats für Gleichheit ein Anfängerfehler ist.

Das Problem besteht darin, dass viele Inkremente, die kleiner sind als ein ganzzahliger Wert, nicht exakt im IEEE Fließkomma dargestellt werden können. Wenn Sie also bei dem Float ankommen, indem Sie versuchen, es auf den Wert von 3,0 zu "indexieren" (sagen wir in Schritten von 0,1), ist es durchaus möglich, dass Ihr Gleichheitsvergleich nie wahr ist.

Es ist auch eine schlechte Idee, nur vom Typstärke Standpunkt. Du solltest entweder den float in einen int umwandeln, dann solltest du prüfen, ob dein int "nahe genug" ist (zB & lt; 3.1 und & gt; 2.9 oder so), oder besser noch, wenn du versuchst, diesen Float für so etwas wie zwei Aufgaben zu machen ein Zähler, vermeiden Sie die ganze Idee.

    
T.E.D. 21.07.2009, 19:58
quelle
13

Dies ist im Allgemeinen (d. h. immer) eine schlechte Idee. Wie Sie vermutet haben, wird der Vergleich zwischen 3 und 3.0000001 tatsächlich fehlschlagen.

Was die meisten Leute tun, wenn ein int-float-Vergleich wirklich notwendig ist, wählen Sie einen Toleranzschwellenwert und gehen Sie damit wie folgt vor:

%Vor%     
Dan Tao 21.07.2009 19:23
quelle
5

Ich werde den Trend hier ein wenig auffrischen. Was die erste Frage betrifft, ob der Vergleich gültig ist, lautet die Antwort ja. Es ist absolut gültig. Wenn Sie wissen möchten, ob ein Fließkommawert genau gleich 3 ist, ist der Vergleich mit einer Ganzzahl in Ordnung. Die ganze Zahl wird implizit in einen Gleitkommawert für den Vergleich umgewandelt. Tatsächlich erzeugte der folgende Code (zumindest mit dem Compiler, den ich verwendete) identische Assembler-Anweisungen.

%Vor%

und

%Vor%

Es kommt also auf die Logik und das angestrebte Ziel an. Es gibt nichts an sich mit der Syntax falsch.

    
Mark Wilkins 21.07.2009 19:44
quelle
4

Niemand hat es bisher zitiert, und ich habe seit einiger Zeit nicht mehr damit zu tun, also hier ist das klassische Papier über die beängstigenden Kanten der Gleitkommadarstellung und -arithmetik: Was jeder Informatiker über Floating Point wissen sollte .

Das Papier ist eine herausfordernde Lektüre für einen Nicht-Mathematiker, aber die Schlüsselpunkte sind zwischen den schweren Matschbanden, die sie unterstützen, gut dargelegt.

Für diese Diskussion sind die Punkte der anderen Antworten gültig. Fließkomma-Arithmetik ist ungenau, und daher sind Vergleiche für exakte Gleichheit in der Regel eine schlechte Idee. Daher ist Epsilon dein Freund.

Eine Ausnahme von der genauen Vergleichsregel ist ein Test für genau Null. Es ist vollkommen legal und oft sinnvoll, vor einer Division oder einem Logarithmus auf genau Null zu prüfen, da die Antwort für irgendeinen von Null verschiedenen Wert gut definiert ist. Natürlich, in Anwesenheit von IEEE-Regeln und NaN, können Sie diese Folie lassen und später auf NaN oder Inf testen.

    
RBerteig 21.07.2009 21:02
quelle
2

Für Ihr spezifisches Beispiel wird "etwas Verrücktes machen" ausgeführt. 3.0 wird zur Laufzeit nicht 3.0000001 sein.

Die anderen Antworten sind mehr für allgemeine Fälle, aber selbst ein hartcodiertes Epsilon ist nicht die größte Idee der Welt. Ein dynamisches Epsilon basierend auf den tatsächlichen Zahlen ist viel besser, da je positiver und negativer die Zahlen sind, desto weniger wahrscheinlich ist das fest codierte Epsilon relevant.

    
Jim Buck 21.07.2009 19:58
quelle
2

Nein, in Ihrem Anwendungsfall gibt es kein Problem, da die Integer genau auf Floats abgebildet werden (es gibt kein Dezimaltrennproblem, wie zum Beispiel bei 0.3; aber 3 ist 1.1E10 in binärer wissenschaftlicher Notation).

Im schlimmsten Fall kann ich mir vorstellen, dass es Integer-Zahlen geben kann, die nicht in float dargestellt werden können, da zwischen zwei aufeinanderfolgenden Gleitkommazahlen "Lücken" größer als 1 sind, aber auch dann, wenn die ganze Zahl geworfen wird Um zu floaten, um den Vergleich zu machen, wird es auf die gleiche Weise wie das Float-Literal auf den nächsten Float gekürzt.

Solange also Ihre Gleitkommazahlen aus nicht-dezimalen Literalen kommen, ist der Vergleich mit der entsprechenden Ganzzahl gleich, da die Ganzzahl vor dem Vergleich in dieselbe Gleitkommazahl umgewandelt wird.

    
fortran 21.07.2009 19:44
quelle
1

Der Kern des Problems ist, dass Gleitkommazahlen, die eine endliche Repräsentation in der Basis 10 haben, dezimal nicht immer eine endliche Repräsentation in der binären Basis 2 haben.

    
IRBMe 21.07.2009 19:25
quelle
1

Sie könnten an der Game Developers Conference Vorlesung Numerische Robustheit für geometrische Berechnungen interessiert sein (aka EPSILON ist NICHT 0.00001!) . Es Details zur Auswahl guter Schwelle / Epsilon-Werte für eine Vielzahl von Aufgaben.

(+ 1 auf der Erwähnung von "Was jeder Informatiker über Fließpunkt wissen sollte" in einer anderen Antwort auch.)

    
leander 21.07.2009 21:15
quelle
0

Wenn der Code wörtlich wie das, was Sie gepostet haben, aussieht (ohne intervenierende Berechnungen), dann kommt es zu der Frage, ob 3.0 und (float)3 (da die ganze Zahl automatisch in einen Float umgewandelt wird) gleich sind. Ich denke, dass sie in diesem Fall garantiert gleich sind, denn 3 ist genau als float darstellbar.

Nebenbei: Und selbst wenn die ganze Zahl nicht genau als Float darstellbar ist (dh wenn sie wirklich groß ist), würde ich mir vorstellen, dass in den meisten Implementierungen x.0 und (float)x gleich wären, denn wie würde die Compiler generiert x.0 an erster Stelle, wenn nicht etwas wie (float)x zu tun? Ich schätze jedoch, dass dies vom Standard nicht garantiert wird.

    
newacct 21.07.2009 19:38
quelle
0

Das ist beängstigend. (Ich frage mich, was du sonst noch findest.)

x wird zum Floaten hochgestuft, aber das wird dir nicht helfen. Wegen der Darstellung von Gleitkommazahlen ist die Verwendung von == zum Vergleichen unzuverlässig.

Ich könnte stattdessen so etwas vorschlagen (auf absolute Fehler / Differenz prüfen):

%Vor%

Dies ist ein allgemeiner Ansatz und kann für Ihre Zwecke ausreichend sein, wenn Ihre Werte von x und y "nett" sind. Wenn Sie wirklich in das Thema des Vergleichens von Floats vertiefen möchten, dieser Artikel hat wahrscheinlich mehr Informationen, als Sie wollen. Es sagt über die Epsilon-Methode:

  

Wenn der Bereich des erwarteten Ergebnisses ist   bekannt, dann auf absolute Fehler überprüfen   ist einfach und effektiv. Mach einfach   sicher, dass dein absoluter Fehlerwert ist   größer als das Minimum darstellbar   Unterschied für die Reichweite und Art von   Float, mit dem du es zu tun hast.

    
JeffH 21.07.2009 19:41
quelle
-1

Bearbeiten :

Der richtige Weg ist die Methode epsilon :

%Vor%     
Sinan Taifour 21.07.2009 19:25
quelle

Tags und Links