Wie funktioniert ein C# auswerten floating point im Schwebeflug über und fortgeschrittene Fenster gegenüber zusammengestellt?

StackOverflow https://stackoverflow.com/questions/1405486

  •  05-07-2019
  •  | 
  •  

Frage

Ich bin da etwas, das seltsam mit der Speicherung Doppel in einem Wörterbuch, und bin verwirrt, warum.

Hier ist der code:

            Dictionary<string, double> a = new Dictionary<string, double>();
            a.Add("a", 1e-3);

            if (1.0 < a["a"] * 1e3)
                Console.WriteLine("Wrong");

            if (1.0 < 1e-3 * 1e3)
                Console.WriteLine("Wrong");

Die zweite if-Anweisung funktioniert wie erwartet;1.0 ist nicht weniger als 1.0.Nun, die erste if-Anweisung als true ausgewertet wird.Das sehr seltsame ist, dass wenn ich den Mauszeiger über den ob, die intellisense mir sagt, false, noch den code gerne bewegt, auf der Konsole.WriteLine.

Dies ist für C# 3.5, Visual Studio 2008.

Dies ist eine floating-point-Genauigkeit problem?Warum dann nicht die zweite if-Anweisung arbeiten?Ich fühle, dass ich bin fehlt etwas sehr grundlegendes hier.

Jeder Einblick wird geschätzt.

Edit2 (Re-purposing Frage ein wenig):

Ich kann akzeptieren, die mathematische Präzision problem, aber meine Frage ist jetzt:warum wird der Mauszeiger über auszuwerten, richtig?Dies gilt auch für die Mittelstufe-Fenster.Ich füge den code aus der ersten if-Anweisung in der Mittelstufe Fenster und es falsch.

Update

Erste von alle, danke sehr viel für all die tollen Antworten.

Ich bin auch Probleme Neuerstellung diese in einem anderen Projekt auf der gleichen Maschine.Blick auf die Projekt-Einstellungen, sehe ich keine Unterschiede.Blick auf die IL zwischen den Projekten, sehe ich keine Unterschiede.Blick auf die Demontage, sehe ich keine offensichtlichen Unterschiede (neben Speicher-Adressen).Aber wenn ich die debug-die ursprüngliche Projekt -, sehe ich:screenshot of problem

Das unmittelbare Fenster sagt mir, die, wenn falsch ist, aber der code stürzt in den conditional.

Jedenfalls hat die beste Antwort, die ich denke, ist die Vorbereitung für Gleitkomma-Arithmetik in diesen Situationen.Den Grund konnte ich es nicht gehen lassen, hat mehr zu tun mit dem debugger Berechnungen abweichend von der Laufzeit.Vielen Dank an Brian Gideon und stephentyrone für einige sehr aufschlussreiche Kommentare.

War es hilfreich?

Lösung

Es schwimmt Präzision Problem.

Zweite Anweisung funktioniert, weil der Compiler den Ausdruck 1e3 zählt * 1e3, bevor die .exe emittiert.

es in ILDasm / Reflector nachschlagen, wird es so etwas wie

emittieren
 if (1.0 < 1.0)
                Console.WriteLine("Wrong");

Andere Tipps

Das problem hier ist ziemlich subtil.Der C# - compiler nicht (immer) emittieren code, der für die Berechnung im Doppel, auch wenn das ist die Art, die Sie angegeben haben.Insbesondere, es gibt code, der für die Berechnung in der "extended" - Präzision mit x87-Anweisungen, ohne Rundung von Zwischenergebnissen zu verdoppeln.

Je nachdem, ob 1e-3 ausgewertet wird, als double oder long double ist, und ob die Multiplikation berechnet wird in double oder long double ist es möglich, eines der folgenden drei Ergebnisse:

  • (long double)1e-3 * 1e3 berechnet long double ist 1.0 - epsilon
  • (Doppel -) 1e-3 * 1e3 berechnete im Doppel ist genau das, 1.0
  • (Doppel -) 1e-3 * 1e3 berechnet long double ist 1.0 + epsilon

Klar, der erste Vergleich, der einem, das nicht Ihren Erwartungen entsprechen ausgewertet wird in der beschriebenen Weise in das Dritte Szenario, das ich aufgeführt.1e-3 wird abgerundet zu verdoppeln, weil Sie entweder speichern Sie es und laden Sie es wieder, die Kräfte, die Rundung, oder, da C# erkennt 1e-3, wie eine double-precision-literal und behandelt es so.Die Multiplikation wird evaluiert, long double, weil C# hat ein Gehirn-tot Numerik Modell das ist die Art und Weise der compiler generiert code.

Die Multiplikation in der zweite Vergleich ist entweder evaluiert mithilfe einer der beiden anderen Methoden, (Sie herausfinden können, welche, indem Sie versuchen, "1 > 1e-3 * 1e3"), oder der compiler rundet das Ergebnis der Multiplikation, bevor der Vergleich mit 1,0, wenn der Ausdruck ausgewertet wird zur compile-Zeit.

Es ist wahrscheinlich möglich für Sie zu sagen, der compiler nicht verwenden erweiterte Präzision, ohne dass Sie sagen, über einige build-Einstellung;aktivieren codegen um SSE2 funktionieren auch.

Sehen Sie die Antworten hier

Umm ... seltsam. Ich bin nicht in der Lage, Ihr Problem zu reproduzieren. Ich bin mit C # 3.5 und Visual Studio 2008 als auch. Ich habe in Ihrem Beispiel getippt genau , wie es geschrieben wurde und ich bin nicht zu sehen, entweder Console.WriteLine Anweisung ausführen.

Auch die zweite if-Anweisung wird immer durch den Compiler optimiert werden. Wenn ich sowohl die Debug- und Release untersuchen in ILDASM / Reflector baut sehe ich keinen Beweis dafür. Das macht da, weil ich eine Compiler-Warnung sagt unerreichbaren Code erhalten wurde auf erkannt.

Schließlich ich sehe nicht, wie dies ohnehin ein Gleitkommagenauigkeit Problem sein könnte. Warum sollte der C # -Compiler bewertet statisch zwei Doppel anders als die CLR würde zur Laufzeit? Wenn das wirklich der Fall wäre, dann könnte man das Argument, dass der C # -Compiler einen Fehler hat.

Edit: Wenn Sie diese ein wenig mehr Gedanken zu machen bin ich noch mehr davon überzeugt, dass dies nicht ein Gleitkommagenauigkeit Problem. Sie müssen entweder über einen Fehler in dem Compiler oder Debugger gestolpert oder der Code, den Sie ist geschrieben nicht genau Vertreter Ihrer eigentlichen Code, der ausgeführt wird. Ich bin sehr skeptisch ein Fehler in dem Compiler, aber ein Fehler im Debugger scheint wahrscheinlicher. Versuchen Sie, das Projekt Wiederaufbau und es wieder zum Laufen. Vielleicht mit exe kompiliert die Debug-Informationen aus Synchronisierung oder etwas auskamen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top