9

Background:Esiste un equivalente g ++ (Linux) per i flag/fp: preciso e/fp: fast utilizzati in Visual Studio?

Molti anni fa, ho ereditato una base di codice che stava usando Visual Studio (VC++) flag '/ fp: fast' per produrre codice più veloce in una particolare libreria di calcolo-pesante. Sfortunatamente, '/ fp: fast' ha prodotto risultati leggermente diversi dalla stessa libreria con un compilatore diverso (Borland C++). Dato che dovevamo produrre esattamente gli stessi risultati, passai a '/ fp: preciso', che funzionava bene, e da allora tutto è stato peachy. Comunque, ora sto compilando la stessa libreria con g ++ su uBuntu Linux 10.04 e sto vedendo un comportamento simile, e mi chiedo se potrebbe avere una causa alla radice simile. I risultati numerici della mia build g ++ sono leggermente diversi dai risultati numerici della mia build VC++. Questo mi porta alla mia domanda:

Domanda:

Fa g ++ avere parametri equivalenti o simili a quelle del 'FP: veloce' e 'fp: precise' opzioni in VC++? (? E quali sono essi che voglio attivare il 'fp: preciso'. Equivalente)

più prolisso informazioni:

compilo usando 'make', che chiama g ++. Per quanto posso dire (i file make sono un po 'criptici e non sono stati scritti da me) gli unici parametri aggiunti alla chiamata g ++ sono quelli "normali" (include cartelle e file da compilare) e -fPIC (Non sono sicuro di cosa funzioni questo interruttore, non lo vedo nella pagina 'man').

Gli unici parametri rilevanti in "man g ++" sembrano essere quelli di attivare le opzioni di ottimizzazione. (ad esempio -funsafe-math-optimizations). Tuttavia, non penso di attivare nulla, voglio solo disattivare l'ottimizzazione pertinente.

Ho provato versioni di debug e di rilascio, VC++ fornisce gli stessi risultati per rilascio e debug e g ++ fornisce gli stessi risultati per rilascio e debug, ma non riesco a ottenere la versione g ++ per ottenere gli stessi risultati del Versione VC++.

+0

Ho trovato il significato di -fPIC dopo un po 'più googling: -fPIC Se supportato per la macchina di destinazione, emette codice indipendente dalla posizione, adatto per il collegamento dinamico, anche se i rami (3, n) necessitano di grandi spostamenti. – Boinst

+0

Questo potrebbe richiedere molto tempo, ma vale la pena: puoi provare e puntare con precisione le prime istruzioni (o almeno la riga di codice) dove alcuni calcoli divergono tra MSVC e gcc? –

+0

Sì, sto lavorando al tuo suggerimento. Sfortunatamente, sono un po 'su un Linux n00b, quindi mi ci vorrà un po' di tempo per mettere insieme tutto! – Boinst

risposta

9

La precisione eccessiva del registro è un problema solo nei registri FPU, che i compilatori (con i giusti interruttori di abilitazione) tendono ad evitare comunque. Quando i calcoli in virgola mobile vengono eseguiti nei registri SSE, la precisione del registro è uguale a quella della memoria.

Nella mia esperienza la maggior parte del/fp: impatto veloce (e discrepanza potenziale) viene dal compilatore che si prende la libertà di eseguire trasformazioni algebriche. Questo può essere semplice come cambiare addendi ordine:

(a + b) + c --> a + (b + c) 

può essere - la distribuzione di moltiplicazioni come un * (b + c) a volontà, e può raggiungere alcune trasformazioni piuttosto complesse - tutti destinati a riutilizzare i calcoli precedenti. In precisione infinita tali trasformazioni sono benigne, ovviamente - ma in una precisione finita cambiano effettivamente il risultato. Come esempio di un giocattolo, prova l'esempio di summend-order con a = b = 2^(- 23), c = 1. Eric Fleegal describes it in much more detail.

In questo senso, l'interruttore gcc più vicino a/fp: preciso è -fno-unsafe-math-optimization. Penso che sia attivo per impostazione predefinita, forse puoi provare a impostarlo esplicitamente e vedere se fa la differenza. Allo stesso modo, puoi provare a disattivare esplicitamente tutte le ottimizzazioni -ffast-math: -fno-finite-math-only, -fmath-errno, -ftrapping-math, -frounding-math e -fsignaling-nans (le ultime 2 opzioni sono non predefinito!)

+0

Grazie per l'idea! 'no-unsafe-math-optimizations' è impostato di default, ma ho provato quello che hai suggerito e impostato in modo esplicito, ma non ha fatto la differenza. – Boinst

+0

Per ora ho "accettato" questa risposta, penso che risponda alla mia domanda anche se sfortunatamente per me non ha risolto il mio problema. :( – Boinst

+0

Mi spiace sentirlo, spero che qualcun altro possa avere un'idea migliore –

4

Non penso che esista un equivalente esatto. Potresti provare -mfpmath=sse invece del valore predefinito -mfpmath=387 per vedere se questo aiuta.

+0

Proverò questa soluzione! – Boinst

+0

Questo non ha aiutato :(ma grazie per l'idea! – Boinst

+0

Quale dovrei usare '-mfpmath = sse' o' -ffloat-store' risolve entrambi il mio problema. – EmptyData

17

Dal GCC manual:

-ffloat-store Non conservare floating point variabili nei registri, e di inibire le altre opzioni che potrebbero cambiare se un valore in virgola mobile è preso da un registro o di memoria.

Questa opzione impedisce un'eccessiva precisione indesiderata su macchine come la 68000 in cui i registri flottanti (del 68881) mantengono più precisione di quanto si suppone un doppio. Allo stesso modo per l'architettura x86. Per la maggior parte dei programmi, la precisione eccessiva fa solo del bene, ma alcuni programmi si basano sulla definizione precisa di virgola mobile IEEE. Utilizzare -ffloat-store per tali programmi, dopo averli modificati per memorizzare tutti i calcoli intermedi pertinenti in variabili.

Per espandere un po ', la maggior parte di queste discrepanze provengono dall'uso dei registri x86 virgola mobile 80 bit per i calcoli (vs 64-bit utilizzati per memorizzare valori double).Se i risultati intermedi vengono mantenuti nei registri senza scrivere nuovamente in memoria, si ottengono effettivamente 16 bit di precisione extra nei calcoli, rendendoli più precisi ma possibilmente divergenti dai risultati generati con la scrittura/lettura di valori intermedi in memoria (o da calcoli su architetture che hanno solo registri FP a 64 bit).

Questi flag (sia in GCC che MSVC) generalmente impongono il troncamento di ogni risultato intermedio a 64 bit, rendendo quindi i calcoli insensibili ai capricci della generazione del codice e alle differenze di ottimizzazione e piattaforma. Questa coerenza viene generalmente accompagnata da un leggero runtime in aggiunta al costo in termini di accuratezza/precisione.

+0

Proverò subito questo – Boinst

+0

Questo non si è rivelato essere il problema, ma grazie per la tua risposta ben ponderata. Il tuo link è stato molto utile – Boinst

+0

Siamo spiacenti di sentirlo. Forse ha qualcosa a che fare con le modalità di arrotondamento? Si può dare un'occhiata all'assemblaggio generato per un programma minimale per il quale si ottengono risultati divergenti e vedere se la FPU è impostata diversamente in MSVC rispetto a GCC. Quindi puoi provare a mappare le impostazioni della FPU a diversi flag del compilatore finché non trovi la bandiera magica. –

1

Questo non è assolutamente correlato ai flag di ottimizzazione, presupponendo che per "Debug" si intende "con le ottimizzazioni disattivate". Se g ++ dà gli stessi risultati nel debug come nel rilascio, ciò significa che non si tratta di un problema correlato all'ottimizzazione. I build di debug devono sempre memorizzare ogni risultato intermedio in memoria, garantendo così gli stessi risultati di/fp: preciso per MSVC.

Questo probabilmente significa che c'è (a) un bug del compilatore in uno dei compilatori, o più probabilmente (b) un bug della libreria matematica. Vorrei approfondire le singole funzioni nei tuoi calcoli e restringere dove si trova la discrepanza. Probabilmente troverai una soluzione alternativa a quel punto, e se trovi un bug, sono sicuro che il team pertinente vorrebbe sentirlo.

+0

Grazie Drew, penso che tu abbia ragione, e farò come suggerisci – Boinst

0

-mpc32 o -mpc64?

Ma potrebbe essere necessario ricompilare C e le librerie matematiche con lo switch per vedere la differenza ... Questo può essere applicato anche ad altre opzioni suggerite.