Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria
Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria
vivo X300 Pro rappresenta un'evoluzione misurata della serie fotografica del produttore cinese, con un sistema di fotocamere migliorato, chipset Dimensity 9500 di ultima generazione e l'arrivo dell'interfaccia OriginOS 6 anche sui modelli internazionali. La scelta di limitare la batteria a 5.440mAh nel mercato europeo, rispetto ai 6.510mAh disponibili altrove, fa storcere un po' il naso
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo
Lenovo Legion Go 2 è la nuova handheld PC gaming con processore AMD Ryzen Z2 Extreme (8 core Zen 5/5c, GPU RDNA 3.5 16 CU) e schermo OLED 8,8" 1920x1200 144Hz. È dotata anche di controller rimovibili TrueStrike con joystick Hall effect e una batteria da 74Wh. Rispetto al dispositivo che l'ha preceduta, migliora ergonomia e prestazioni a basse risoluzioni, ma pesa 920g e costa 1.299€ nella configurazione con 32GB RAM/1TB SSD e Z2 Extreme
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti
A re:Invent 2025, AWS mostra un’evoluzione profonda della propria strategia: l’IA diventa una piattaforma di servizi sempre più pronta all’uso, con agenti e modelli preconfigurati che accelerano lo sviluppo, mentre il cloud resta la base imprescindibile per governare dati, complessità e lock-in in uno scenario sempre più orientato all’hybrid cloud
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 17-10-2011, 16:33   #1
Zero-Giulio
Member
 
Iscritto dal: May 2007
Messaggi: 292
[C++] Meccaniche segrete del compilatore

Ok, premetto che non sono un grande esperto di programmazione.
Magari quello che mi succede è normalissimo e nessuno di voi si stupirebbe. Ma a me sembra inspiegabile e quindi vi chiedo lumi.

Guardate un attimo queste 5 righe di codice:

Codice:
double value = 0.0;
value += (ptr->_pdd * ptr->_ndd->_temp3);
value += (ptr->_pdu * ptr->_ndu->_temp3);
value += (ptr->_pud * ptr->_nud->_temp3);
value += (ptr->_puu * ptr->_nuu->_temp3);
Niente di che. La variabile double value viene inizializzata a zero, e successivamente incrementata 4 volte.

Ora guardate queste 3 righe di codice:

Codice:
double temp = 0.0;
double ttt = (ptr->_pdd * ptr->_ndd->_temp3)
              + (ptr->_pdu * ptr->_ndu->_temp3)
              + (ptr->_pud * ptr->_nud->_temp3)
              + (ptr->_puu * ptr->_nuu->_temp3);
temp = ttt;
Anche qui, nulla di strano. Nella variabile double ttt sommo 4 addendi, e poi a temp assegno ttt.

Notate che i 4 addendi nei due estratti di codice sono gli stessi.

Io sarei portato a pensare che value e temp assumano lo stesso valore. E invece NO!!!

Qualcuno sa spiegarmi perchè?

C'è qualcosa che mi sfugge, ma non so cosa. I miei colleghi non riescono ad aiutarmi.

Ovviamente posso darvi tutte le informazioni che volete sul codice in questione, anche se non credo siano molto rilevanti.
Per la cronaca, ptr è un puntatore a un oggetto, il quale oggetto ha, tra gli altri attributi, il double temp3, 4 double (pdd, pdu, pud, puu) e 4 puntatori a oggetti come lui.
Quindi le variabili temp, ttt, value, ptr->pxy e ptr->nxy->temp3 (per x, y = u, d) sono tutte double.

La situazione in sostanza è questa.
Immaginate di avere un albero. I nodi dell'albero sono le strutture di sopra (hanno 4 probabilità e 4 puntatori ad altrettanti nodi, più vari double temporanei).
A questo punto io faccio un ciclo sui nodi dell'albero, e in corrispondenza di ogni nodo mi calcolo il value (vedi codice sopra) e il temp (vedi codice sopra), e li confronto. Ovviamente tra il value e il temp non faccio niente. Sono uno dopo l'altro. Il puntatore ptr viene utilizzato solo in lettura.
Quindi confronto value e temp. E sono diversi.

Qualcuno sa spiegarmi cosa succede?

P.S. ovviamente posso allegare il mio codice se qualcuno non crede a quello che mi succede.
Zero-Giulio è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 17:03   #2
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
A colpo d'occhio non vedo problemi.
Che valori hanno le variabili incriminate ? E che valori ottieni ? (cosi' intanto capiamo in quale dei due pezzi di codice le cose vanno male).
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 17:24   #3
Zero-Giulio
Member
 
Iscritto dal: May 2007
Messaggi: 292
Non si tratta di valori giusti o sbagliati.
Non saprei neanche quale dei due sia quello giusto, giacchè le differenze sono sulla quindicesima/sedicesima cifra decimale.
Il punto è che non sono uguali, e io non capisco perchè.
Non ci sono conversioni, e il tipo e l'ordine delle operazioni dovrebbe essere lo stesso (per dire, lo so che in aritmetica a precisione finita le operazioni non sono associative, o altri dettagli di questo tipo... Ma nel mio caso dovrebbe essere tutto perfettamente identico).
Zero-Giulio è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 17:28   #4
Unrue
Senior Member
 
L'Avatar di Unrue
 
Iscritto dal: Nov 2002
Messaggi: 6399
Codice:
double temp = 0.0;
double ttt = (ptr->_pdd * ptr->_ndd->_temp3)
              + (ptr->_pdu * ptr->_ndu->_temp3)
              + (ptr->_pud * ptr->_nud->_temp3)
              + (ptr->_puu * ptr->_nuu->_temp3);
temp = ttt;
In questo caso non conosci l'ordine delle somme, che non necessariamente sono eseguite nell'ordine che hai scritto se attivi le ottimizzazioni ( -O3 ad esempio). Quindi, essendo la somma tra floating point non commutativa, puoi avere valori diversi tra i due casi.

Nel tuo caso potrebbe bastare disabilitare TUTTI i flags di ottimizzazione ( -O0 ad esempio), per verificare in fase di debug se i risultati tra i due casi coincidono.

A+B != B+A con A e B floating point.

Ultima modifica di Unrue : 17-10-2011 alle 17:36.
Unrue è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 17:56   #5
Zero-Giulio
Member
 
Iscritto dal: May 2007
Messaggi: 292
Ma quindi secondo te è un problema di ordine delle operazioni?
Io ho sempre pensato che l'ordine delle operazioni lo decidessi al moemento di scrivere materialmente il codice.
Cmq flag di ottimizzazione non ne ho.
Sviluppo con un ide, CodeBlocks, ma nella finestra dei flag ho solo -Wall
Zero-Giulio è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 18:05   #6
Unrue
Senior Member
 
L'Avatar di Unrue
 
Iscritto dal: Nov 2002
Messaggi: 6399
Quote:
Originariamente inviato da Zero-Giulio Guarda i messaggi
Ma quindi secondo te è un problema di ordine delle operazioni?
Supponendo che prima di quelle somme non ci siano altri bug nel codice, si.


Quote:
Originariamente inviato da Zero-Giulio Guarda i messaggi
Ma quindi secondo te è un problema di ordine delle operazioni?
Io ho sempre pensato che l'ordine delle operazioni lo decidessi al moemento di scrivere materialmente il codice.

No, quello che è garantito è la correttezza delle operazioni anche se vengono scambiate l'ordine di alcune di esse. Ovviamente non ti può modificare la logica del codice.


Quote:
Originariamente inviato da Zero-Giulio Guarda i messaggi
Cmq flag di ottimizzazione non ne ho.
Sviluppo con un ide, CodeBlocks, ma nella finestra dei flag ho solo -Wall
Controlla che il compilatore non inserisca flags di ottimizzazione e poi metti esplicitamente -O0

Ultima modifica di Unrue : 17-10-2011 alle 18:07.
Unrue è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 18:12   #7
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da Unrue Guarda i messaggi
No, quello che è garantito è la correttezza delle operazioni anche se vengono scambiate l'ordine di alcune di esse. Ovviamente non ti può modificare la logica del codice.
Uhm, ma l'operatore + in c++ associa a sinistra, quindi l'ordine dovrebbe essere ben definito
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 18:45   #8
Zero-Giulio
Member
 
Iscritto dal: May 2007
Messaggi: 292
Domani proverò con l'O0...
Vedremo...
Zero-Giulio è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 22:43   #9
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da Unrue Guarda i messaggi
No, quello che è garantito è la correttezza delle operazioni anche se vengono scambiate l'ordine di alcune di esse. Ovviamente non ti può modificare la logica del codice.
La mia ipotesi e' un po' diversa: nel primo caso il valore temporaneo viene sempre riportato ogni volta nella variabile temporanea, per cui in memoria
Nel secondo caso il compilatore puo' aver benissimo deciso di lasciare il risultato intermedio nel registro della FPU che nel caso di CPU x86 ha precisione interna maggiore.
Poi provo a verificare guardando il codice generato nei due casi.
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 17-10-2011, 23:10   #10
LMCH
Senior Member
 
Iscritto dal: Jan 2007
Messaggi: 6290
Quote:
Originariamente inviato da Zero-Giulio Guarda i messaggi
Qualcuno sa spiegarmi cosa succede?
Sei entrato nel fantabosco del floating point, dove vivono i NaN(senza i), gli zeri mannari ed altre bestie strane ...
e dove gli errori di troncamento ti possono far uscire pazzo.

Più semplicemente con i valori in floating point ad ogni operazione che fai, hai un risultato che in generale è un approssimazione del "vero" risultato.

Ad esempio i double hanno una mantissa normalizzata a 56bit (in realtà 55 con il 56-esimo implicitamente sempre ad 1), se fai una moltiplicazione o una divisione ti servirebbe una mantissa di 112bit (56+56 bit) per avere il risultato esatto-esatto e con somma sottrazione è anche peggio (se uno dei due numeri ha un esponente troppo piccolo rispetto all'altro, è come sommare o sottrarre zero a causa del "troncamento implicito della mantissa").

Per questo motivo sugli x86 se si usa la FPU (invece delle istruzioni SSE) le operazioni vengono eseguiti su registri a precisione estesa (64bit di mantissa e 16bit di esponente, se ricordo bene).
Quando poi scrivi il risultato in memoria su una variabile double per troncamento o arrotondamento perdi di brutto 8 bit di mantissa.

Nel primo spezzone di codice, dopo ogni moltiplicazione (fatta su registri interni) sommavi il risultato e lo memorizzavi su una variabile double, quindi producevi un troncamento/arrotondamento dopo ogni moltiplicazione e somma quando ri-memorizzi il risultato (per un totale di 4 troncamenti che ogni volta tranciano via 8 bit "residui").

Nel secondo spezzone di codice hai fatto tutte le moltiplicazioni e somme in un unica espressione, tenendo i valori intermedi sui registri a precisione estesa
ed alla fine fai un solo troncamento finale per memorizzare il risultato.

Se il compilatore non fa altri giochini di ottimizzazione ecc. ecc. è quindi quello a produrre valori differenti, ma di solito ci si mette pure il compilatore (specialmente se si usano opzioni che accelerano le operazioni a discapito della precisione).

Esistono comunque degli standard su "come gestire correttamente i floating point secondo gli standard IEEE" in modo da ridurre le "differenze di risultato" (non si tratta di avere più precisione, ma di avere risultati abbastanza coerenti.

Con i compilatori Microsoft puoi usare le opzioni /fp ( http://msdn.microsoft.com/en-us/library/e7s85ffb.aspx ).

Con GCC ci sono -ffloat-store -fexcess-precision=... oppure puoi forzare l'uso di solo sse2 in modo da non usare la precisione estesa (-mfpmath=sse -msse2 ecc. ecc.).
ecc. ecc.
Per maggiori dettagli dai un occhiata qui: http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
(per trovare quello che ti interessa, vai avanti fino a quando con -ffloat-store inizia la lista delle opzioni che controllano precisione ed ottimizzazioni del floating point).

Normalmente le "differenze di comportamento" sono trascurabili, ma ovviamente in certi casi bisogna fare molta attenzione per evitare che succedano cose strane.
E' per questo che in certi casi per simulazioni scientifiche o per elaborazioni in cui l'accumulazione di errori potrebbe essere pericolosa, si usano librerie che garantiscono maggiore "stabilita dei risultati" tipo MPFR (http://www.mpfr.org/ ) o GMP ( http://gmplib.org/ )
LMCH è offline   Rispondi citando il messaggio o parte di esso
Old 18-10-2011, 09:52   #11
Unrue
Senior Member
 
L'Avatar di Unrue
 
Iscritto dal: Nov 2002
Messaggi: 6399
Quote:
Originariamente inviato da marco.r Guarda i messaggi
Uhm, ma l'operatore + in c++ associa a sinistra, quindi l'ordine dovrebbe essere ben definito
A meno di trucchi di ottimizzazione .

La cosa migliore in questi casi è analizzare l'assembly generato.
Unrue è offline   Rispondi citando il messaggio o parte di esso
Old 19-10-2011, 18:55   #12
Zero-Giulio
Member
 
Iscritto dal: May 2007
Messaggi: 292
Uh, mi sa che sono proprio gli errori che troncamento.
Che noia 'sti double, se i numeri non sono uguali non posso usare WinMerge per fare i test di non regressione (trovo mille mila ddifferenze, anceh se tutte nelle ultime cifre).

Vabbè, oggi non ho avuto molto tempo per testare se veramente è questo il problema (il mio boss mi ammazza se rimango fermo sullo stesso punto per la sedicesima cifra decimale). Magari prox ci ritorno su.

Cmq grazie mille a tutti per le dritte.
Zero-Giulio è offline   Rispondi citando il messaggio o parte di esso
Old 20-10-2011, 09:13   #13
Unrue
Senior Member
 
L'Avatar di Unrue
 
Iscritto dal: Nov 2002
Messaggi: 6399
Quote:
Originariamente inviato da Zero-Giulio Guarda i messaggi
Uh, mi sa che sono proprio gli errori che troncamento.
Che noia 'sti double, se i numeri non sono uguali non posso usare WinMerge per fare i test di non regressione (trovo mille mila ddifferenze, anceh se tutte nelle ultime cifre).

Vabbè, oggi non ho avuto molto tempo per testare se veramente è questo il problema (il mio boss mi ammazza se rimango fermo sullo stesso punto per la sedicesima cifra decimale). Magari prox ci ritorno su.

Cmq grazie mille a tutti per le dritte.
In realtà se il tuo algoritmo è immune ad errori dalla sedicesima cifra decimale puoi anche ignorarli. Ovviamente se invece dà instabilità devi contenerli.
Unrue è offline   Rispondi citando il messaggio o parte di esso
Old 20-10-2011, 10:04   #14
Zero-Giulio
Member
 
Iscritto dal: May 2007
Messaggi: 292
Qualche instabilità la da.
L'albero mi serve per la valutazione di alcuni prodotti finanziari, e questa procedura è inserita in un algoritmo di ottimizzazione per la calibrazione dei parametri del modello sui dati di mercato.
Poichè l'algoritmo di ottimizzazione lavora con le derivate numeriche, errori alla sedicesima cifra sui prezzi diventano errori alla ottava cifra nella matrice dello jacobiano e da li in poi...
Nulla di che, alla fine l'output della calibrazione è lo stesso alla settima cifra (e a me tipicamente servono solo le prime 4-5 cifre).

Diciamo che era più che altro curiosità intellettuale.
Io non riuscivo a spiegarmi in cosa potessero differire le due versioni del codice.
Io non sapevo, per dire, dei registri a precisione estesa...
Zero-Giulio è offline   Rispondi citando il messaggio o parte di esso
Old 20-10-2011, 17:40   #15
LMCH
Senior Member
 
Iscritto dal: Jan 2007
Messaggi: 6290
Quote:
Originariamente inviato da Zero-Giulio Guarda i messaggi
Nulla di che, alla fine l'output della calibrazione è lo stesso alla settima cifra (e a me tipicamente servono solo le prime 4-5 cifre).
Se vuoi maggior precisione puoi usare le librerie che avevo indicato in precedenza, in particolare la GMP
ed il suo port per MSVC++ MPIR.
LMCH è offline   Rispondi citando il messaggio o parte di esso
Old 21-10-2011, 10:01   #16
Zero-Giulio
Member
 
Iscritto dal: May 2007
Messaggi: 292
Ai tempi dell'uni avevo lavorato con la CLN (class library for numbers), e ricordo non ne ero rimasto troppo affascinato.
Credo che la CLN si appoggiasse alla GMP, o sbaglio?
Boh, son passati parecchia anni, non ricordo...
Zero-Giulio è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria Recensione vivo X300 Pro: è ancora lui il...
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'...
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti AWS re:Invent 2025: inizia l'era dell'AI-as-a-Se...
Cos'è la bolla dell'IA e perché se ne parla Cos'è la bolla dell'IA e perché se...
BOOX Palma 2 Pro in prova: l'e-reader diventa a colori, e davvero tascabile BOOX Palma 2 Pro in prova: l'e-reader diventa a ...
Il seguito di Cyberpunk 2077 si farà att...
Dov'è finita la parola "sost...
Gli agenti IA saranno il fulcro delle az...
Data center: un mercato da 30 miliardi d...
Licenziato e sostituito dall'AI? In Cina...
HONOR Magic 8 Pro: abbiamo tra le mani i...
OPPO ha appena svelato un tablet di fas...
Peaky Blinders: The Immortal Man, Netfli...
iPhone Air: la nuova generazione potrebb...
Il Galaxy S26 Ultra avrà una batteria da...
EV Clinic cambia un settore: ora produce...
OnePlus ha anticipato l'arrivo della ver...
Amazon ha sospeso la sperimentazione del...
Mark Hamill sarà per sempre Luke ...
Amazon rilancia i bestseller fra cui un ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 21:34.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v