Warum müsste ein Informatiker eine eigene Version von std :: complex implementieren?
14
Viele der in der Computerwissenschaft bekannteren C ++ - Bibliotheken wie Eigen , Trilinos und deal.II verwenden das Standardobjekt der C ++ - Headerbibliothek , std::complex<>um komplexe Gleitkommazahlen darzustellen.
In Jack Poulsons Antwort auf eine Frage zu Standardkonstruktoren weist er darauf hin, dass er "aus mehreren Gründen" eine eigene Implementierung von std::complexin Elemental hat . Was sind diese Gründe? Was sind die Vor- und Nachteile dieses Ansatzes?
Ich glaube, diese Diskussion ist mehrfach auf der PETSc-Liste aufgetaucht. Meine Hauptgründe sind:
Der C ++ - Standard besagt, dass std :: complex nur für die Datentypen float, double und long double definiert ist. Daher kann es nicht für andere Datentypen wie Quad-Genauigkeit verwendet werden.
Die Norm gibt keine Gewähr für die Stabilität der komplexen Arithmetik.
Der Standard übernimmt keine Garantie dafür, dass die Daten in einem std :: complex als reale Komponente gefolgt von der imaginären Komponente gespeichert werden. Dies ist für Schnittstellen zu externen Bibliotheken wie BLAS und LAPACK von entscheidender Bedeutung. Dies gilt für alle wichtigen Implementierungen, aber ich würde es vorziehen, dies sicherstellen zu können.
Ich bevorzuge es, die realen und imaginären Komponenten direkt manipulieren zu können. std :: complex erschwert dies unnötig.
Ich möchte irgendwann eine allgemeinere Version haben, bei der der Datentyp nur ein Ring sein muss, anstatt ein Feld zu benötigen. Dies würde die Gaußschen Ganzzahlen einschließen.
Punkt 3 wurde in C ++ 11 angesprochen. 26.4.4 besagt, dass wenn zein Wertausdruck vom Typ cvstd::complex<T> ist reinterpret_cast<cv T(&)[2]>(z)und reinterpret_cast<cv T(&)[2]>(z)[0]den Realteil von zund reinterpret_cast<cv T(&)[2]>(z)[1]den Imaginärteil von bezeichnen soll z. Auch Arrays komplexer Zahlen werden angesprochen.
James Custer
3
@JamesCuster: Ich bin alle dafür, irgendwann auf C ++ 11 umzusteigen, aber wissenschaftliche Codes, die auf semi-exotische Architekturen portierbar bleiben wollen, müssen wahrscheinlich noch mindestens zwei bis drei Jahre warten, um dies zu tun. Auch C ++ 11 behebt leider nur einen Teil des Problems.
Jack Poulson
Ich verstehe, ich habe es nur rausgeworfen, falls sich jemand in Zukunft mit dieser Frage befasst.
James Custer
2
Nun, ich denke, es ist eine Ausrede zu sagen, dass Sie warten müssen, bis Compiler C ++ 11 unterstützen. Die ausdrückliche Anforderung wurde in den neuen Standard aufgenommen, da alle vorhandenen Implementierungen dies bereits unterstützen. Ich kann mir keinen Fall vorstellen, in dem es unsicher wäre, dieses spezielle Layout bereits in vorhandenen Compilern / Bibliotheken zu übernehmen, da es einfach keinen Sinn gemacht hätte, std :: complex auf andere Weise zu implementieren.
Wolfgang Bangerth
1
@WolfgangBangerth: Es war eher ein allgemeiner Kommentar zum Umstieg auf C ++ 11. In beiden Fällen behebt C ++ 11 die meisten Probleme mit std :: complex nicht.
Jack Poulson
7
Ich verwende es std::complex<>in meinen Programmen und muss bei jedem neuen Compiler oder Compiler-Upgrade mit Compiler-Flags und Workaround kämpfen. Ich werde versuchen, diese Kämpfe in chronologischer Reihenfolge wiederzugeben:
std::norm| z|2| z|-ffast-math
Der Intel ICC-Compiler unter Linux (oder Linker) wurde std::argunter bestimmten Konfigurationen zu einem Nicht-Opt- Compiler kompiliert (Link-Kompatibilität mit einer bestimmten GCC-Version). Das Problem tauchte zu oft auf und std::argmusste durch ersetzt werden atan2(imag(),real()). Aber es war allzu leicht, dies beim Schreiben von neuem Code zu vergessen.
Der Typ std::complexverwendet andere Aufrufkonventionen (= ABI) als der integrierte C99-Komplextyp und der integrierte Fortran-Komplextyp für neuere gcc-Versionen.
Das -ffast-mathCompile-Flag interagiert auf unerwartete Weise mit der Behandlung von Gleitkomma-Ausnahmen. Was passiert, ist, dass der Compiler Divisionen aus Schleifen zieht und dadurch division by zerozur Laufzeit Ausnahmen verursacht . Diese Ausnahmen wären niemals innerhalb der Schleife aufgetreten, da die entsprechende Aufteilung aufgrund der umgebenden Logik nicht erfolgte. Das war wirklich schlecht, denn es war eine Bibliothek, die getrennt von dem Programm kompiliert wurde, das die Gleitkomma-Ausnahmebehandlung (unter Verwendung verschiedener Kompilierungsflags) verwendete und auf diese Probleme stieß (die entsprechenden Teams saßen also in entgegengesetzten Teilen der Welt) Dieses Problem verursachte wirklich schlimme Probleme. Dies wurde behoben, indem die vom Compiler verwendete Optimierung mit größerer Sorgfalt von Hand durchgeführt wurde.
Die Bibliothek wurde Teil des Programms und verwendete das -ffast-mathCompile-Flag nicht mehr . Nach einem Upgrade auf eine neuere gcc-Version sank die Leistung um einen großen Faktor. Ich habe dieses Problem noch nicht im Detail untersucht, befürchte jedoch, dass es mit Anhang G zu C99 zusammenhängt . Ich muss zugeben, dass ich durch diese seltsame Definition der Multiplikation für komplexe Zahlen völlig verwirrt bin, und es scheint sogar verschiedene Versionen davon zu geben, mit der Behauptung, dass die anderen Versionen falsch sind. Ich hoffe, dass das -fcx-limited-rangeCompile-Flag das Problem lösen wird, da es ein weiteres Problem mit -ffast-mathdieser neueren gcc-Version zu geben scheint .
Das -ffast-mathCompile-Flag macht das Verhalten NaNfür neuere Versionen von gcc (auch wenn isnanes betroffen ist) völlig unvorhersehbar . Die einzige Problemumgehung scheint darin zu bestehen, jegliches Auftreten NaNim Programm zu vermeiden , das den Zweck für die Existenz von zunichte macht NaN.
Nun können Sie sich fragen, ob ich die eingebauten komplexen Typen std::complexaus diesen Gründen verwerfen möchte. Ich werde bei den eingebauten Typen bleiben, solange ich bei C ++ bleibe. Für den Fall, dass C ++ für das wissenschaftliche Rechnen völlig unbrauchbar werden sollte, würde ich eher in Betracht ziehen, auf eine Sprache umzuschalten, die die für das wissenschaftliche Rechnen relevanten Aspekte besser berücksichtigt.
Meine Befürchtungen in Bezug auf C99-Anhang G haben sich offenbar erfüllt, und für eine anständige Rechengeschwindigkeit beim Multiplizieren komplexer Zahlen ist jetzt ein -fcx-beschränkter Bereich erforderlich. Zumindest ist das, was ich aus der folgenden jüngsten Kriegsgeschichte bekomme
z
ein Wertausdruck vom Typ cvstd::complex<T>
istreinterpret_cast<cv T(&)[2]>(z)
undreinterpret_cast<cv T(&)[2]>(z)[0]
den Realteil vonz
undreinterpret_cast<cv T(&)[2]>(z)[1]
den Imaginärteil von bezeichnen sollz
. Auch Arrays komplexer Zahlen werden angesprochen.Ich verwende es
std::complex<>
in meinen Programmen und muss bei jedem neuen Compiler oder Compiler-Upgrade mit Compiler-Flags und Workaround kämpfen. Ich werde versuchen, diese Kämpfe in chronologischer Reihenfolge wiederzugeben:std::norm
-ffast-math
std::arg
unter bestimmten Konfigurationen zu einem Nicht-Opt- Compiler kompiliert (Link-Kompatibilität mit einer bestimmten GCC-Version). Das Problem tauchte zu oft auf undstd::arg
musste durch ersetzt werdenatan2(imag(),real())
. Aber es war allzu leicht, dies beim Schreiben von neuem Code zu vergessen.std::complex
verwendet andere Aufrufkonventionen (= ABI) als der integrierte C99-Komplextyp und der integrierte Fortran-Komplextyp für neuere gcc-Versionen.-ffast-math
Compile-Flag interagiert auf unerwartete Weise mit der Behandlung von Gleitkomma-Ausnahmen. Was passiert, ist, dass der Compiler Divisionen aus Schleifen zieht und dadurchdivision by zero
zur Laufzeit Ausnahmen verursacht . Diese Ausnahmen wären niemals innerhalb der Schleife aufgetreten, da die entsprechende Aufteilung aufgrund der umgebenden Logik nicht erfolgte. Das war wirklich schlecht, denn es war eine Bibliothek, die getrennt von dem Programm kompiliert wurde, das die Gleitkomma-Ausnahmebehandlung (unter Verwendung verschiedener Kompilierungsflags) verwendete und auf diese Probleme stieß (die entsprechenden Teams saßen also in entgegengesetzten Teilen der Welt) Dieses Problem verursachte wirklich schlimme Probleme. Dies wurde behoben, indem die vom Compiler verwendete Optimierung mit größerer Sorgfalt von Hand durchgeführt wurde.-ffast-math
Compile-Flag nicht mehr . Nach einem Upgrade auf eine neuere gcc-Version sank die Leistung um einen großen Faktor. Ich habe dieses Problem noch nicht im Detail untersucht, befürchte jedoch, dass es mit Anhang G zu C99 zusammenhängt . Ich muss zugeben, dass ich durch diese seltsame Definition der Multiplikation für komplexe Zahlen völlig verwirrt bin, und es scheint sogar verschiedene Versionen davon zu geben, mit der Behauptung, dass die anderen Versionen falsch sind. Ich hoffe, dass das-fcx-limited-range
Compile-Flag das Problem lösen wird, da es ein weiteres Problem mit-ffast-math
dieser neueren gcc-Version zu geben scheint .-ffast-math
Compile-Flag macht das VerhaltenNaN
für neuere Versionen von gcc (auch wennisnan
es betroffen ist) völlig unvorhersehbar . Die einzige Problemumgehung scheint darin zu bestehen, jegliches AuftretenNaN
im Programm zu vermeiden , das den Zweck für die Existenz von zunichte machtNaN
.Nun können Sie sich fragen, ob ich die eingebauten komplexen Typen
std::complex
aus diesen Gründen verwerfen möchte. Ich werde bei den eingebauten Typen bleiben, solange ich bei C ++ bleibe. Für den Fall, dass C ++ für das wissenschaftliche Rechnen völlig unbrauchbar werden sollte, würde ich eher in Betracht ziehen, auf eine Sprache umzuschalten, die die für das wissenschaftliche Rechnen relevanten Aspekte besser berücksichtigt.quelle