8 Stimmen

C++ / C# Unterschiede bei float und double

Wir konvertieren eine C++-Mathematikbibliothek nach C#. Die Bibliothek mischt die Verwendung von Floats und Doubles (Casting zwischen ihnen manchmal) und wir versuchen, das gleiche zu tun, um die genau die gleichen Ergebnisse in C# zu erhalten, die wir in C++ hatten, aber es erweist sich als sehr schwierig, wenn nicht unmöglich.

Ich denke, das Problem ist eines oder mehrere der folgenden, aber ich bin kein Experte:

  1. Die Umwandlung von Floats in Double und Double in Floats führt zu unvorhersehbaren Ergebnissen und wird in C++ und C# unterschiedlich gehandhabt.

  2. C++ und C# gehen unterschiedlich mit der Genauigkeit von Fließkommazahlen um und können sich nicht gegenseitig imitieren.

  3. Irgendwo in .NET gibt es eine Einstellung, mit der es wie C++ funktioniert, aber ich kann sie nicht finden (beide sind 32-Bit)

Kann mir jemand die möglichen Probleme erklären und mir vielleicht einen Link zu einer maßgeblichen Dokumentation von Microsoft geben, die ich verwenden kann, um die Situation und den Grund für die Unterschiede zu erklären?

EDIT
Wir verwenden VC6 und .NET4.0

Wegen eines NDA kann ich keine Beispiele für die Berechnungen geben, aber ich kann einige Zahlen für die Unterschiede aufzeigen... wahrscheinlich sehr nutzlos für sich selbst:

 8.085004000000000 (C#) vs. 
 8.084980000000000 (C++)    

 8.848165000000000 (C#) vs. 
 8.848170000000000 (C++)   

 0.015263214111328 (C#) vs. 
 0.015263900756836 (C++)  

Es sei darauf hingewiesen, dass diese Zahlen auch zusammengesetzte Probleme enthalten. Dies sind die Ergebnisse von Berechnungen.

10voto

Pascal Cuoq Punkte 77147

C++ ermöglicht es dem Programm, eine höhere Genauigkeit für Zwischenergebnisse beizubehalten, als es der Typ der Unterausdrücke implizieren würde. So kann es vorkommen, dass Zwischenausdrücke (oder eine nicht spezifizierte Teilmenge davon) als erweiterte 80-Bit-Fließkommazahlen berechnet werden.

Andererseits wäre ich überrascht, wenn dies auf C# zuträfe, aber selbst wenn dies der Fall ist, muss der C#-Compiler nicht dieselbe Teilmenge von Ausdrücken auswählen, um sie als 80-Bit-Extended Floats zu berechnen. EDIT: Siehe Erics Kommentar unten.

Mehr Details

Ein weiteres Beispiel für das gleiche Problem der Zwischenpräzision ist, wenn der Compiler die fmadd Anweisung für eine Multiplikation, gefolgt von einer Addition im Quellcode (falls die Zielarchitektur über eine solche verfügt, z. B. PowerPC). Die fmadd Anweisung berechnet ihr Zwischenergebnis exakt, während eine normale Addition das Zwischenergebnis runden würde.

Um zu verhindern, dass der C++-Compiler dies tut, sollten Sie Fließkommaberechnungen nur als Drei-Adressen-Code schreiben und flüchtige Variablen für Zwischenergebnisse verwenden. Wenn diese Umwandlung das Ergebnis des C++-Programms verändert, bedeutet dies, dass das obige Problem im Spiel war. Aber dann haben Sie die C++-seitigen Ergebnisse verändert. Es gibt wahrscheinlich keine Möglichkeit, in C# genau die gleichen alten C++-Ergebnisse zu erhalten, ohne die generierte Assembly zu lesen.

Wenn Ihr C++-Compiler schon etwas älter ist, optimiert er möglicherweise auch Fließkommaberechnungen so, als ob sie assoziativ wären, obwohl sie es nicht sind. Dagegen können Sie nicht viel tun. Es ist einfach falsch. Die Drei-Adressen-Code-Transformation würde wiederum verhindern, dass der Compiler sie anwendet, aber auch hier gibt es keine einfache Möglichkeit, den C#-Compiler dazu zu bringen, die alten C++-Ergebnisse zu reproduzieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X