2015-06-16 85 views
5

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
+1

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

+0

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? –

+0

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

Antwort

1

Die Antwort auf Ihre Frage ist: Ja, im Prinzip kann ein Prozess den Fließkommakontext ändern, in dem Ihr Code arbeitet.


Über Ihre speziellen Code und Werte:

Der Rundungsmodus (wie Matteo schon sagt) könnte beeinflussen Zeichenfolge Formatierung, wie es immer wieder um 10 teilt - aber ich kann das Problem mit std::fesetround nicht reproduzieren .

Ich kann auch nicht sehen, wie es wirklich das Bit-Muster beeinflussen würde Sie sagen, war anders. Der Assembly-Code zeigt das Literal 0x45329000, das 2857.0 entspricht, und das Literal selbst kann nicht durch den Fließkomma-env geändert werden.

+0

Nicht sicher, ob dies Informationen hinzufügen, aber beachten Sie, dass ich beim Streamen nach Cout eine Protokollierung auf den Wert 2857 durchführen. Das Ergebnis dieses Protokolls unterscheidet sich. Der Wert 2857 selbst scheint nicht zu sein. –