PDA

View Full Version : controllo precisione fpu


cndcnd
31-08-2011, 15:35
Ciao,

Per un'applicazione geometrica scritta in c++ utilizzo due piattaforme, una è un laptop con:

- windows
- compilatore gcc
- processori intel

l'altra è un cluster con:

- linux
- compilatore gcc
- processori intel

Il problema è che, pur essendo il codice lo stesso, i risultati numerici sono (leggermente) diversi. Ho provato a inserire il codice seguente, che dovrebbe consentire di controllare la precisione della fpu:

void set_fpu (unsigned int mode)
{
asm ("fldcw %0" : : "m" (*&mode));
}

set_fpu (0x27F); /* use double-precision rounding */

Purtroppo non funziona :-( Avete qualche idea?

Grazie,

Alex

AnonimoVeneziano
31-08-2011, 15:41
Prova in fase di compilazione a disabilitare eventuali ottimizzazioni del processore.

Se entrambe le piattafome supportano SSE prova ad usare queste flags

"-O2 -march=i686 -mfpmath=sse -msse2"

oppure potresti usare

"-O2 -march=i686 -mfpmath=387"

Se non riesci a risolvere prova a giochicchiare con le flags di compilazione, in particolare per disabilitare tutte le ottimizzazioni :

"-O0 -march=i386 -mtune=i386 -mfpmath=387"

Usare la STESSA versione di GCC potrebbe aiutare ad avere risultati consistenti, perchè magari il codice generato è leggermente diverso

Ciao

PS= ovviamente per usare la doppia precisione assicurati di stare usando dei double nel tuo programma :p

marco.r
31-08-2011, 17:10
Verifica quali ottimizzazioni relative all'fpu sono abilitate (di default?) nei due ambienti.
In particolare se vuoi rendere la cosa piu' portabile, devi forzare un comportamento conforme allo standard (al prezzo di performance potenzialmente piu' basse).
Prova a dare una occhiata alle varie flag relative di gcc. Un "sospetto" potrebbe essere -fexcess-precision visto che di default con nel caso di sse usa la precisione definita dallo standard, mentre nel caso dell'fpu no.

cndcnd
01-09-2011, 14:49
@ anonimo veneziano: "PS= ovviamente per usare la doppia precisione assicurati di stare usando dei double nel tuo programma!". In realtà ci sono anche parecchi float, ma non capisco perchè questo fatto dovrebbe c'entrare. A me non interessa che i risultati siano precisi, io voglio soltanto che venga fuori lo stesso risultato.

@ Marco. Non posso disabilitare le ottimizzazioni, la versione sul cluster dev’essere più veloce possibile, mentre l’altra mi serve per il debug. Comunque l’unico flag che utilizzo in compilazione è –O3.

In ogni caso adesso sto cercando di usare double dappertutto, poi provo a rimettere il codice di controllo della FPU e vediamo.

marco.r
01-09-2011, 15:03
@ Marco. Non posso disabilitare le ottimizzazioni, la versione sul cluster dev’essere più veloce possibile, mentre l’altra mi serve per il debug. Comunque l’unico flag che utilizzo in compilazione è –O3.

Non puoi pretendere di avere risultati consistenti da una macchina all'altra se abiliti delle ottimizzazioni che sono dipendenti dalla piattaforma sottostante. Secondo me dovresti almeno fare una prova per verificare se il problema sta proprio li'.
Magari scopri che sono quelle sulla tua macchina ad essere colpevoli (esempio: magari il cluster utilizza istruzioni SSE con precisione 64 bit, mentre il tuo pc utilizza l'FPU, con una precisione di 80 bit per i dati intermedi)

AnonimoVeneziano
01-09-2011, 16:14
Come ha detto marco se usi ottimizzazioni diverse per le due macchine i risultati possono essere diversi. In particolare devi assicurarti che entrambe le macchine usino le stesse unità floating point (o entrambi quelle SSE o entrambi la FPU 387) perchè la FPU 387 usa una precisione interna a 80bit e poi per farlo stare in un double il risultato viene riscalato a 64 bit, mentre la FPU SSE utilizza la precisione a 64 bit per i calcoli interni e questa cosa può creare risultati differenti se su una macchina usi 387 e sull'altra SSE .

Inoltre se non ti interessa la precisione, ma preferisci la velocità allora potresti pensare di usare l' ottimizzazione "-ffast-math" che più di qualsiasi altra ottimizzazione velocizza i calcoli con la FPU a scapito però della compliance con lo standard IEEE per i calcoli in virgola mobile. Se usando "-ffast-math" non si rompe niente allora sei a cavallo :)

cndcnd
02-09-2011, 12:12
Grazie per le risposte ragazzi, sto facendo delle prove. A proposito, al compilatore microsoft visual studio l'istruzione:

asm ("fldcw %0" : : "m" (*&mode));

non piace. Non gli piace nemmeno:

_asm ("fldcw %0" : : "m" (*&mode));

Sapete qual'è la versione giusta?

AnonimoVeneziano
02-09-2011, 14:14
Grazie per le risposte ragazzi, sto facendo delle prove. A proposito, al compilatore microsoft visual studio l'istruzione:

asm ("fldcw %0" : : "m" (*&mode));

non piace. Non gli piace nemmeno:

_asm ("fldcw %0" : : "m" (*&mode));

Sapete qual'è la versione giusta?

Su windows penso che sia meglio usare questa API:

http://msdn.microsoft.com/en-gb/library/e9b52ceh.aspx