Wir haben ein Problem mit Gleitkomma-Genauigkeit in einer dynamischen Bibliothek.Kann eine ausführbare Datei in Linux die Fließkomma-Genauigkeit in einer verknüpften dynamischen Bibliothek beeinflussen?
Der Aufbau ist wie folgt:
- Wir haben eine dynamische Bibliothek, die von Gleitkommazahlen eine Berechnung X auf einem großen Array durchführt. X besteht aus vielen Fließkommaoperationen.
- Wir verknüpfen diese dynamische Bibliothek zu zwei ausführbaren Dateien: A und B.
- Innerhalb der Bibliothek ich den Eingang für die Berechnung X.
- Für beide ausführbaren A und B genau die gleiche Eingabe wird berichtet, drucken (bis zu DBL_DIG Dezimalstellen).
- Der Ausgang der Berechnung X, unterscheidet sich jedoch für ausführbare A, als es für ausführbare B. ist
Beide ausführbaren Dateien und die Bibliothek werden in C++ geschrieben und auf der gleichen Maschine kompiliert die gleiche GCC Compiler Version unter Verwendung . Die Bibliothek wird nur einmal mit denselben Compilereinstellungen wie ausführbare Datei A kompiliert, aber die Compilereinstellungen für ausführbare Datei B können unterschiedlich sein.
Da dieselbe Bibliothek verwendet wird, erwarteten wir die gleiche Berechnungspräzision für beide ausführbaren Dateien, wenn dieselbe Eingabe bereitgestellt wurde. Es sieht so aus, als ob die Gleitkommapräzision der Bibliothek durch äußere Faktoren beeinflusst wird, z. prozessspezifische Konfigurationen
Ist dies möglich und wenn ja, wie kann sichergestellt werden, dass wir die gleiche Genauigkeit in beiden Läufen erhalten (Programm A und B)?
bearbeiten 1
ich gelungen, ein minimales Beispiel zu schaffen, die die Unterschiede aufzeigt. Wenn ich den folgenden Code in der Bibliothek (beispielsweise Berechnung X) Die Ergebnisse sind für beide Läufe (A und B):
float* value = new float;
*value = 2857.0f;
std::cout << std::setprecision(15) << std::log(*value) << std::endl;
I auch die Hin- und Herbewegungen im binären Format gedruckt, und sie zeigen einen Unterschied in der letztes Stück.
Leider kann nicht die gesamte Build-Kette von ausführbaren A steuern. Eigentlich ist A wieder eine dynamische Bibliothek, die von einer anderen ausführbaren Datei verwendet wird, für die ich die Compiler-Optionen nicht steuern kann.
Ich habe versucht, viele verschiedene Optimierung Compiler-Optionen auf ausführbare B zu verwenden, um zu sehen, ob ich die gleichen Ergebnisse wie für ausführbare A erhalten kann, aber bis jetzt hat dies das Problem nicht gelöst.
Edit 2
Der Assembler Ausgabe des obigen Code ist:
.LFB1066:
.cfi_startproc
.cfi_personality 0x9b,DW.ref.__gxx_personality_v0
push rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
push rbx #
.cfi_def_cfa_offset 24
.cfi_offset 3, -24
sub rsp, 8 #,
.cfi_def_cfa_offset 32
mov edi, 4 #,
call [email protected] #
mov DWORD PTR [rax], 0x45329000 #* D.23338,
mov rdi, QWORD PTR [email protected][rip] # tmp66,
mov rax, QWORD PTR [rdi] # cout._vptr.basic_ostream, cout._vptr.basic_ostream
mov rax, QWORD PTR -24[rax] # tmp68,
mov QWORD PTR 8[rax+rdi], 15 # <variable>._M_precision,
movsd xmm0, QWORD PTR .LC1[rip] #,
call [email protected] #
mov rbx, rax # D.23465,
mov rax, QWORD PTR [rax] # <variable>._vptr.basic_ostream, <variable>._vptr.basic_ostream
mov rax, QWORD PTR -24[rax] # tmp73,
mov rbp, QWORD PTR 240[rbx+rax] # D.23552, <variable>._M_ctype
test rbp, rbp # D.23552
je .L9 #,
cmp BYTE PTR 56[rbp], 0 # <variable>._M_widen_ok
je .L5 #,
movsx esi, BYTE PTR 67[rbp] # D.23550, <variable>._M_widen
bearbeiten 3
Wie in den Kommentaren schlug ich sowohl die Gleitkomma Rundungsmodus gedruckt und SSE-Statusinformationen in der Bibliothek.
Für beide Läufe (ausführbare A und B) ich die gleichen Werte erhalten:
- Rounding-Modus: 895
- SSE-Status: 8114
Wird eine der Binärdateien mit einem hohen Optimierungsgrad kompiliert? Einige Ebenen ermöglichen möglicherweise unsichere Berechnungen oder ändern die Standardgenauigkeit. Siehe: https://gcc.gnu.org/wiki/FloatingPointMath für eine Liste von Schaltern, die das Verhalten von Gleitkommaoperationen in GCC ändern. – Matthew
Ich muss das nachsehen. Ich werde morgen darauf zurückkommen. Aber bedeutet das, dass die Kompilierungseinstellungen der ausführbaren Datei die Genauigkeit innerhalb der bereits kompilierten gemeinsam genutzten Bibliothek beeinflussen können? –
Ja, wenn die Option die Standard-Float-Breite oder das Berechnungsverhalten ändert. Versuchen Sie, die tatsächlichen Bytes der Variablen innerhalb der Bibliothek zu drucken, und verwenden Sie printf nicht, um zu sehen, ob sie korrekt dargestellt werden, und verwenden Sie "-ffloat-store" für alle Kompilierungen, um sicherzustellen, dass die Breite gleich bleibt. Als erstes sollten Sie "-O0" auf alle Compilations anwenden, um zu sehen, ob das das Problem behebt. – Matthew