PDA

View Full Version : [Generico] problema con Floating-Point


Simonex84
24-04-2009, 14:38
Ho un problemino con i Floating-Point a singola precisione (32 bit)

Supponiamo di avere un programma che riceve in input un vettore di valori del tipo:

+2.124587e+000
-1.458789e+000
.....

poi per ogni valore fa questa operazione:

costante := +6.874521e+000

val := (val*val*2.0)*costante

e poi scrive in output tutti i val.

Bene se faccio girare questo programmino su un PowerPC 745 e su un Intel x86 a volte ho dei risutati diversi sull'ultima cifra di precisione, per esempio ho:

su ppc +2.485674e+000
su x86 +2.485675e+000

Non riesco a capire cosa succede, visto che le due cpu usano lo standard IEEE 754 dovrebbero fare calcoli ed approssimazioni nello stesso identico modo.

può essere legato al fatto che x86 è little-endian e il ppc è big-endian??

gugoXX
24-04-2009, 14:51
I float sono definiti in modo diverso anche nello standard IEEE
intendo, ci sono float a 32bit, a 64bit, a 128bit e anche ad 80bit (non proprio standard standard ma accettati ed estesi)
Il coprocessore degli intel internamente opera a 80bit, i PPC non penso, ma non penso comunque solo a 32bit come i tuoi input.
In pratica durante il caricamento dei registri del coprocessore avviene una conversione, una estensione.
I calcoli vengono fatti a 80bit, e poi quando vengono ritirati vengono di nuovo passati a 32bit per essere usati dal tuo programma.
Ecco quindi che i risultati possono essere leggermente diversi, pur attenendosi entrambi i processori allo standard IEEE.

Simonex84
24-04-2009, 15:24
ma quindi quando l'intel passa da 32 a 80 bit i 48 bit di differenza cosa fa li riempie a caso??

Adesso sul manuale del ppc con quanti bit lavora il coprocessor

gugoXX
24-04-2009, 15:49
ma quindi quando l'intel passa da 32 a 80 bit i 48 bit di differenza cosa fa li riempie a caso??

Adesso sul manuale del ppc con quanti bit lavora il coprocessor

Ma mica a caso dai.
C'e' una corrispondenza ovvia per ciascun float a 32bit e un float a 80bit. Non si perde nulla ne si deve inventare nulla.
La parte restante della mantissa viene riempita con tutti 0, e l'esponente pure. Ovviamente un float a 32bit puo' essere scritto a 80bit senza problemi o ambiguita'.

Diverso e' invece il troncamento da 80bit a 32bit, essendo che la corrispondenza e' necessariamente multipla. Ma per questo ci sono gli algoritmi preposti dallo IEEE per il troncamento.

BrutPitt
24-04-2009, 15:54
ma quindi quando l'intel passa da 32 a 80 bit i 48 bit di differenza cosa fa li riempie a caso??

Adesso sul manuale del ppc con quanti bit lavora il coprocessor

No, vengono usati per eliminare la propagazione degli errori derivante dall'aumento di precisone dovuto ad operazioni consecutive.

Oltre a quanto scritto da gugoXX e aggiungo....

A volte dipende anche dal compilatore e dai "default" di compilazione... e possono veraiare da versione a versione, e da macchina a macchina.
Nel senso che alcuni compilatori, sapendo che affronteranno operazioni sul float, operano internamente in doppia precisione (sempre per il discorso propagazione errore), oltre che su registri del processore anche sul salvataggio temporaneo del risultato in aree di memoria "double"... altri usano le estenzioni SS2 a 128bit, se disponibile... altri in modalita' "fast-float" mantenendo celle di memoria a 32bit, sempre.
(e molte opzioni sono forzabili all'atto della compilazione)

Tralascio la "machine accuracy", che e' diversa dalla precisione di rappresentazione IEEE, e che solitamente e' rivolta alle funzioni complesse (sqrt, pow, sin, cos... etc.)... ma bisognerebbe dare anche un occhiata all'accuratezza della "printf" dei 2 compilatori, o chi per lei.

Insomma i fattori possono essere diversi... sicuramente non e' il fatto che uno sia big-endian e l'altro little-endian.

Simonex84
24-04-2009, 15:57
Si in effetti ho detto una ca##ta, oggi sono fuso :D

Quindi alla fine intel carica i float a 32 bit in nel coprecessor a 80 bit fa i calcoli a 80 bit e poi un casting a 32 bit del risultato.

Il powerppc usando un coprecessor a 64 bit è meno preciso nei calcoli e lo scostamento deriva da questo.

Potresti dirmi dove hai trovato l'informazione che l'x86 usa un coprecessor a 80 bit??

Simonex84
24-04-2009, 16:01
Tralascio la "machine accuracy", che e' diversa dalla precisione di rappresentazione IEEE, e che solitamente e' rivolta alle funzioni complesse (sqrt, pow, sin, cos... etc.)... ma bisognerebbe dare anche un occhiata all'accuratezza della "printf" dei 2 compilatori, o chi per lei.

Gli output li scrivo in binario e poi li converto in ascii con matlab quindi tra le due versioni in questa fase non possono esserci differenze.

BrutPitt
24-04-2009, 16:22
Gli output li scrivo in binario e poi li converto in ascii con matlab quindi tra le due versioni in questa fase non possono esserci differenze.

Allora una cosa in meno da controllare :)

Puoi vedere la rappresentazione interna dei registri FPU sul manuale Intel dell'IA32:
http://download.intel.com/design/processor/manuals/253665.pdf

Oppure graficamente anche qui:
http://www.sandpile.org/ia32/fp_old.htm

Simonex84
24-04-2009, 17:14
Allora una cosa in meno da controllare :)

Puoi vedere la rappresentazione interna dei registri FPU sul manuale Intel dell'IA32:
http://download.intel.com/design/processor/manuals/253665.pdf

Oppure graficamente anche qui:
http://www.sandpile.org/ia32/fp_old.htm

Ottimo, grazie mille!!!! lunedì il mio capo sarà molto contento :D

cdimauro
24-04-2009, 20:18
A volte dipende anche dal compilatore e dai "default" di compilazione... e possono veraiare da versione a versione, e da macchina a macchina.
Nel senso che alcuni compilatori, sapendo che affronteranno operazioni sul float, operano internamente in doppia precisione (sempre per il discorso propagazione errore), oltre che su registri del processore anche sul salvataggio temporaneo del risultato in aree di memoria "double"... altri usano le estenzioni SS2 a 128bit, se disponibile... altri in modalita' "fast-float" mantenendo celle di memoria a 32bit, sempre.
(e molte opzioni sono forzabili all'atto della compilazione)
Le SSE2 a 128 bit, però, operano sempre con double. Non ci sono ancora float a 128 bit.
Insomma i fattori possono essere diversi... sicuramente non e' il fatto che uno sia big-endian e l'altro little-endian.
Concordo: questo non c'entra niente.