2015-06-16 15 views
5

Stiamo riscontrando un problema con la precisione in virgola mobile all'interno di una libreria dinamica.Un eseguibile in Linux può influenzare la precisione in virgola mobile all'interno di una libreria dinamica collegata?

Il set-up è la seguente:

  • Abbiamo una libreria dinamica, che esegue un calcolo X su una vasta gamma di numeri in virgola mobile. X consiste in molte operazioni in virgola mobile.
  • colleghiamo questa libreria dinamica per due eseguibili: A e B.
  • All'interno della libreria Stampiamo l'ingresso per il calcolo X.
  • Per entrambi eseguibili in esecuzione A e B è riportato esattamente lo stesso ingresso (fino a DBL_DIG decimali).
  • L'uscita della computazione X, tuttavia, è diverso per eseguibile A quanto lo sia per eseguibile B.

Sia eseguibili e la libreria sono scritte in C++ e compilato sulla stessa macchina utilizzando la versione del compilatore stesso GCC . La libreria viene compilata una sola volta con le stesse impostazioni del compilatore dell'eseguibile A, ma le impostazioni del compilatore per l'eseguibile B potrebbero essere diverse.

Come la stessa libreria viene utilizzata, ci si aspettava la stessa precisione di calcolo per entrambi gli eseguibili quando si fornisce lo stesso input. Sembra che la precisione in virgola mobile della libreria sia influenzata da fattori esterni, ad es. elaborare configurazioni specifiche.

È possibile e, in tal caso, come si può essere sicuri di ottenere la stessa precisione in entrambe le esecuzioni (programma A e B)?

Modifica 1

sono riuscito a creare un esempio minimo che dimostra le differenze. Se uso il seguente codice nella libreria (diciamo come calcolo X) i risultati sono diversi per entrambe le corse (A e B):

float* value = new float; 
*value = 2857.0f; 
std::cout << std::setprecision(15) << std::log(*value) << std::endl; 

Ho anche stampato i carri in formato binario e mostrano una differenza nella ultimo bit.

Purtroppo non è possibile controllare l'intera catena di build dell'eseguibile A. In realtà A è di nuovo una libreria dinamica che viene utilizzata da un altro eseguibile per il quale non posso controllare né conoscere le opzioni del compilatore.

Ho provato a utilizzare molte diverse opzioni del compilatore di ottimizzazione sull'eseguibile B per vedere se riesco a ottenere gli stessi risultati dell'eseguibile A, ma fino ad ora questo non risolveva il problema.

Edit 2

L'uscita assemblatore del codice precedente è:

.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 

Edit 3

Come suggerito nei commenti ho stampato sia la modalità punto di arrotondamento flottante e Informazioni sullo stato SSE nella libreria.

Per entrambe le corse (eseguibile A e B) ottengo gli stessi valori:

modalità
  • Arrotondamento: 895
  • SSE Stato: 8114
+1

Uno dei binari viene compilato con un livello elevato di ottimizzazione? Alcuni livelli potrebbero consentire la matematica non sicura o modificare la precisione predefinita. Vedi: https://gcc.gnu.org/wiki/FloatingPointMath per un elenco di opzioni che modificano il comportamento delle operazioni in virgola mobile in GCC. – Matthew

+0

Devo cercare questo. Tornerò su di esso domani. Ma questo significa che le impostazioni di compilazione dell'eseguibile possono influenzare la precisione all'interno della libreria condivisa già compilata? –

+0

Sì, se l'opzione modifica la larghezza flottante predefinita o il comportamento del calcolo. Prova a stampare i byte effettivi delle variabili all'interno della libreria e non utilizzare printf per vedere se sono rappresentati correttamente, e usa '-ffloat-store' su tutte le compilation per assicurarti che la larghezza rimanga invariata. In via preliminare dovresti forzare '-O0' su tutte le compilation per vedere se questo risolve il problema. – Matthew

risposta

1

La risposta alla tua domanda è: Sì, in linea di principio un processo può modificare il contesto in virgola mobile all'interno del quale il codice opera.


Chi vostra particolare codice e valori:

Il la modalità di arrotondamento (come suggerisce Matteo) potrebbe influenzare la formattazione delle stringhe in quanto divide più volte dal 10 - ma non riesco a riprodurre il problema utilizzando std::fesetround .

Inoltre non riesco a vedere come potrebbe davvero influire sul pattern di bit che hai detto fosse diverso. Il codice assembly mostra il valore letterale 0x45329000, che è equivalente a 2857.0, e il letterale stesso non può essere modificato dall'env in virgola mobile.

+0

Non sono sicuro se questo aggiunge informazioni, ma nota che in streaming su cout eseguo un log sul valore 2857. Il risultato di questo registro è diverso. Il valore 2857 stesso non sembra. –