Come garantire gli stessi numeri a virgola mobile su sistemi diversi?

Se compilo seguendo le linee c su windows e linux (ubuntu) ottengo risultati diversi. Vorrei evitare Come posso farlo?

double a = DBL_EPSILON; double b = sqrt(a); printf("eps = %.20e\tsqrt(eps) = %.20e\n", a, b); 

output linux:

 eps = 2.22044604925031308085e-16 sqrt(eps) = 1.49011611938476562500e-08 

uscita di Windows:

 eps = 2.22044604925031310000e-016 sqrt(eps) = 1.49011611938476560000e-008 

Su linux testato con gcc e clang sullo stesso risultato del sistema a 32-bit e 64-bit. Su Windows testato con gcc-mingw su 32-bit e visual-studio con 32-bit e 64-bit, anche gli stessi risultati.

Nell’esempio che date, sembra che entrambi i programmi abbiano gli stessi numeri in virgola mobile. Li stampano in modo diverso. La soluzione più semplice intorno a questo particolare problema è scrivere la propria funzione di stampa a virgola mobile. Se non ti aspetti un’uscita troppo bella, potresti usare la funzione qui come pseudocodice per scrivere la tua in C. Non è arrotondata correttamente, ma funziona per quello a cui è destinata (cioè, output riproducibili e leggibili).


Un problema più profondo che le tue domande suggeriscono che stai incontrando sono calcoli a virgola mobile che danno risultati diversi su piattaforms diverse. Questo è il risultato dello standard C che non obbliga i compilatori a implementare lo standard IEEE 754 a virgola mobile esattamente, in particolare, consentendo una maggiore precisione per i risultati intermedi. E questa relativa clemenza dello standard C è causata almeno in parte dalle istruzioni x86 a virgola mobile storiche che rendono costoso implementare l’esatta semantica IEEE 754.

Su Linux, supponendo che si stia utilizzando GCC, provare l’opzione di compilazione -msse2 . EDIT: l’OP ha commentato che -msse2 -mfpmath=sse funzionato per lui. In questo modo GCC genera istruzioni SSE2 moderne che forniscono esattamente la semantica a virgola mobile IEEE 754. Se su Windows stai usando GCC, usa la stessa opzione lì.

Se si utilizza Visual C: Visual C utilizza un altro trucco per forzare le istruzioni storiche in virgola mobile in modo che corrispondano alla semantica IEEE 754: indica al vecchio hardware a virgola mobile a 80 bit di utilizzare solo il numero di bit e bit di IEEE 754 a doppia precisione ha. Ciò fornisce una simulazione accurata dei numeri a precisione doppia, ad eccezione di alcuni casi angolari che non si incontreranno. In questo caso sarebbe utile (*) se il tuo programma usasse solo numeri a doppia precisione (il tipo C double ).

(*) Il compilatore Visual C potrebbe teoricamente generare codice che calcola l’esatta aritmetica a precisione singola arrotondando ogni risultato intermedio dalla doppia alla singola precisione, ma sarebbe costoso e dubito che lo faccia.