Newsgroup: it.scienza.fisica
Titolo: Simulazione fisica C++: float o double ?

Volevo "giocherellare" un po' con le leggi della dinamica, e creare una 
piccola simulazione di moto in C++.
Ho pero' dei dubbi su quale tipo scegliere per i numeri reali: qualcuno 
che ha esperienza a riguardo, potrebbe per piacere illuminarmi se sia 
meglio usare double o float?
Io opterei per i double, che hanno precisione doppia rispetto ai float 
(anche se occupano il doppio della memoria)...pero' non so se la potenza 
dei double e' "sprecata"...oppure se invece, usando i float, otterei 
errori nella simulazione, dovuti a troncamenti e approssimazioni 
numeriche grossolane.
Grazie per un'eventuale risposta.
Ciao,
Dan

 meglio usare double o float?
[...]
Oilà... finalmente una domanda "di fisica" alla quale posso rispondere, 
senza timore di essere contraddetto... di assembly decisamente ne capisco 
;))))). Ma tu dirai: io parlo del C++, non dell'assembly. Come ben sai, 
qualunque linguaggio tu usi, viene sempre compilato poi in assembly. Più 
propriamente si dovrebbe parlare di linguaggio macchina, ma non siamo 
pignoli, in questo contesto. Se, come suppongo, utilizzi un PC con CPU 
Pentium, puoi usare tranquillamente i double. Il Pentium effettua i calcoli 
in virgola mobile molto velocemente, indipendentemente dal fatto che si 
usino i float od i double. Se consulti un manuale dell'assembly Pentium, 
vedrai che ci sono istruzioni, come FMUL, che richiedono solo da 1 a 3 
cicli, per essere eseguite.
Potrai notare un rallentamento, con i double invece dei float, in alcuni 
casi, legati alla dimensione della cache. Avere dati più piccoli, li 
potrebbe far stare completamente nella memoria cache della CPU, migliorando 
così le prestazioni. Appena i dati (anche float) superano la dimensione 
della cache, il vantaggio si perde totalmente.
Il mio consiglio, da programmatore, è quello di definire un tuo tipo di 
dati:
typedef double numero;
da usare in tutti i punti del programma in cui scriveresti double o float. 
In questo modo, devi solo modificare questa riga, per cambiare "al volo" la 
precisione dei calcoli e fare esperimenti velocemente. Ad esempio:
numero CalcolaDistanza2d(numero xa,numero ya,numero xb,numero yb)
{
  numero deltax=xa-xb;
  numero deltay=ya-yb;
  return sqrt(deltax*deltax+deltay*deltay);
}
Un altro caso in cui usare float/double potrebbe fare la differenza è, come 
nell'esempio, nella chiamata di funzioni matematiche che prevedono già un 
tipo di dato particolare. La radice quadrata è implementata, dal 
compilatore, per i vari tipi di dati numerici (float/double ecc.). Molto 
probabilmente, l'implementazione non fa altro che chiamare l'equivalente 
istruzione FSQRT del Pentium, lo stesso per seno, coseno ecc. Alcune 
funzioni potrebbero però essere risolte "da codice", invece che sfruttando 
la CPU. Dipende dal compilatore, ma, in genere, ritengo che comunque siano 
più efficienti con i double.
Ho recentemente verificato personalmente che non c'è una differenza 
apprezzabile, addirittura nell'usare tipi interi o double, per il calcolo 
matriciale. Questo è vero per il Pentium. Se usi altre CPU, non lo posso 
affermare, non conoscendole (per altre CPU intendo quelle con architettura 
diversa dal Pentium, non quelle compatibili con le CPU Intel).
Infine, se la simulazione è molto pesante, ti consiglio di analizzare il 
codice assembly generato dal compilatore. In molti casi, lo si può 
ulteriormente ottimizzare a mano, sia riscrivendolo direttamente in assembly 
sia cambiando qualcosa nell'algoritmo in C++. In questo modo, ho 
quadruplicato la velocità di rendering di punti in una mia applicazione di 
modellazione solida... quindi so cosa sto dicendo ;))))
Stefano

 Dan
Dipende da cosa vuoi tu!
Se vuoi una simulazione molto accurata allora usa i double, se no usa i
float.
Comunque io userei i float, perche' non avrai mai una simulazione accurata.
Infatti devi considerare il tempo, che in una simulazione al computer deve
necessariamente essere discreto. Quindi introdurrai in ogni caso un errore.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it


Premessa. Piu' che di float o double occorrerebbe parlare di 
rappresentazioni a 32 o 64 bit. Considerando la situazione attuale, 
usero' float e double come sinonimo (improprio) di 32 o 64 bit.
In genere l'integrazione delle equazioni del moto e' meno affetta da 
problemi di precisione di altri  campi computazionali. Questo vuol dire 
che con i float si puo' lavorare. Pero' se siano o meno adeguati dipende 
molto da cosa si deve fare. Con la rappresentazione standard (IEEE754) 
per i numeri floating point si puo' contare su una precisione relativa 
di dell'ordine di 10^-7 per i float e di 10^-16 per i double.
Questa precisione controlla  l'errore di arrotondamento che si 
ripercuote in vario modo sui risultati.
Nel caso dell'integrazione delle equazioni del moto c'e' sicuramente una 
seconda sorgente di errore che e' l'errore di discretizzazione dell' 
algoritmo di integrazione utilizzato. Qui ci sono varie possibilita' 
"sul mercato" , ognuna con la sua dipendenza dell' errore dal time step 
di integrazione.
In pratica, qualsiasi sia la scelta,  ci saranno due tendenze 
contrastanti: se riduci il time step riduci l' errore di 
discretizzazione ma aumenti quello di arrotondamento e viceversa.
Un modo per decidere se l'integrazione e' corretta e' quello di 
utilizzare la presenza di costanti del moto nel problema esatto per 
verificare l' adeguatezza dei parametri numerici (e degli algoritmi) 
prescelti.
Allora, se vuoi/hai bisogno di conservare le costanti del moto con alta 
  precisione  sicuramente occorrera' usare double. Se invece non hai 
esigenze estreme potresti anche usare i float.
Questo dal punto di vista di principio.
In pratica il raddoppiamento nell' occupazione di memoria dei double e' 
difficilmente un serio problema (a meno che tu non voglia simulare 
miliardi di particelle). Quanto ai tempi di esecuzione, dipende dalla 
macchina su cui gira il programma, dal compilatore e dalla codifica. Non 
ci sono regole  precise e la versione double potrebbe essere piu' lenta, 
equivalente o piu' veloce di quella float. Meglio fare dei test e, sulla 
base dei risultati decidere cosa fare.
Il mio consiglio e'  comunque di optare per la versione double a meno 
che tu non abbia delle esigenze particolari.
Giorgio

 meglio usare double o float?
La scelta del tipo di variabili da utilizzare dipende da molti fattori.
Suppongo dall'e-mail precedente, che tu voglia fare una simulazione n-corpi.
In tal caso molto dipende dall'algoritmo che utilizzi e dal numero di corpi
che
fanno parte del sistema simulato. Se ad esempio, utilizzi per la risoluzione
approssimata delle equazioni del moto, il metodo di Eulero, allora avrai
un errore dello stesso ordine di grandezza dello step temporale (o(h)).
Dunque, se l'errore dovuto al tuo metodo di calcolo è superiore all'errore
di arrotondamento che si commette utilizzando i float, non c'è problema.
Ad esempio, se utilizzi uno step temporale di h=0.0001 ad esempio, l'errore
di arrotondamento
commesso utilizzando i float viene totalmente assorbito dall'errore
intrinseco dell'algoritmo.
Se invece (per assurdo -perche' in realtà non è conveniente-) utilizzi un
Runge-Kutta del secondo
ordine avrai che l'errore è se non mi sbaglio un o(h^2) quindi utilizzando
lo step temporale precedente
avresti che gli errori di troncamento non sono più trascurabili rispetto
all'errore intrinseco dell'algoritmo.
Insomma per dirla breve, devi verificare se l'errore intrinseco dovuto al
metodo di integrazione utilizzato
è paragonabile all'errore di arrotondamento dovuto al formato float. Se si
ti conviene passare ai double,
altrimenti usa i float che occupano meno memoria e sono più veloci.
A presto!
--
Pasquale Galianni

essere eseguite.
Potresti consigliarmi uno di questi manuali se ce n'e` in
italiano?
Io son rimasto all'"80386 Architettura e programmazione",
di A. Cattania, della Jackson.
TIA:-))
-- 
Ciao,		|   Attenzione! campo "Reply-To:"  alterato	|
Remigio Zedda	|   posta: ti.ilacsit@zoigimer  <-- dx/sn  ;^)	|
	-- GNU/Linux 2.4.25 su Slackware 9.1

 numero CalcolaDistanza2d(numero xa,numero ya,numero xb,numero yb)
In questi casi invece, trattandosi di C++ userei definizioni con i template!
template<typename numero>
numero CalcolaDistanza2d(numero xa,numero ya,numero xb,numero yb)
{
        //...
}
Scusate l'OT.

 meglio usare double o float?
Ciao,
con le comuni rappresentazioni a 32 (float) e 64 bit (double) tipiche che
troviamo nei nostri PC, ti consiglio quando non ci sono problemi
prestazionali o di occupazione di memoria (non è il tuo caso) di usare
comunque i double.
La precisione dei float a volte è veramente grossolana quando i numeri
passano attraverso moltiplicazioni, divisioni, elevamenti a potenze.
Nelle applicazioni scientifiche si usano solitamente i double, se non vi
sono ottimi motivi per utilizzare i float (solitamente prestazioni od
occupazione di memoria).

occupazione di memoria).
Sono daccordo, ammenochè tu non voglia simulare un sistema di un milione di 
corpi, usa i double e vai sul sicuro!
PG 

 ha scritto nel messaggio
news:cpcv76$hjb$1...@lacerta.tiscalinet.it...

Concordo, anch'io uso pesantemente i template. In questo caso, però è più
semplice, per un "fisico programmatore", usare un banale typedef. Anche
perchè i template devi poi usarli in ogni funzione e ti appesantiscono sia
il sorgente che (ma non in questo caso) l'eseguibile generato.
Siccome l'informatica è ormnai uno strumento qusais indispensabile, anche
per il fisico, fors enon siamo poi troppo OT. Ma hai ragione... meglio
fermarsi qui (magari ci spostiamo su it.scienza.informatica, che è meno
trafficato).
Stefano
PS: a rez consiglio "Il manuale del Pentium" di Michael L.Schmit, edizioni 
Mc Graw Hill - ISBN 88-386-0367-7; io ho l'edizione del '96, che è un po' 
datata. Ho trovato molto professionali i libri di questa casa editrice, un 
po' meno quelli della casa indicata da rez (giudizio personale, basato solo 
sui libri da me letti)

PS: a rez consiglio "Il manuale del Pentium" di Michael L.Schmit, edizioni 
TNX! :-)
Perfettamente d'accordo anch'io col tuo giudizio
complessivo sulle due case editrici.


 corpi, usa i double e vai sul sicuro!
Uso questo post per fare un ringraziamento generale a tutti.
Ho capito che mi conviene i double, anche perche' non devo simulare "un 
milione di corpi" :) ma volevo semplicemente fare esperimenti con 
F = ma
cambiando la F e vedendo cosa viene fuori, es.: se uno avesse una 
gravita' che va come 1/r o 1/r^3, volevo vedere che orbite avrebbero i 
pianeti, etc.
Volevo fare anche delle prove di moto di un proiettile, ipotizzando 
pero' la resistenaza dell'aria (quindi non piu' la banale parabola che 
si ha quanto non vi e' resistenza al moto).
E poi volevo verificare alcuni teoremi di conservazione "in maniera 
empirica", vedendo anche la simulazione quanto si discosta dalle 
previsioni teoriche.
Come integrazione (cioe': per risalire da a alla posizione) pensavo 
semplicemente di approssimare le derivata con un rapporto incrementale 
finito, cioe':
y' = dy/dx circa= [Delta]y/[Delta]x
Quindi calcolo:
dy = y' dx
allora se conosco x0 e y0 (condizioni iniziali), avro':
y1 = y0 + y' * dx
y2 = y1 + y' * dx
etc.
Non so se questo ingenerera' errori grossolani [spero di no :)]
Ciao,
Dan

Ti dico subito che concordo con tutti quelli che ti hanno consigliato
il tipo double.
A rigore si dovrebbe dire "dipende", e tu non hai dato nessuna
informazione su che tipo di calcoli vuoi fare: "giocherellare con le
leggi della dinamica" e' un po' poco...
Ma suppongo che non ti meterai a studiare sistemi di 1000 corpi, e
forse neppure di 10. Quindi i problemi di occupazione di memoria o di
cache non li avrai di certo, ne' avrai problemi di tempo di calcolo.
Invece un certo rischio di eccessivi errori di arrotondamento potresti
averlo, quindi opto per il double che non ha praticamente svantaggi in
questo caso.
Viceversa, come ti e' gia' stato detto e ribadisco, dovresti fare
attenzione all'algoritmo d'integrazione che userai.
Ti sconsiglio risolutamente il cosiddsetto "metodo di Eulero", ossia
delle differenze prime in avanti.
E' poco preciso, quindi ti obbliga a un piccolo passo temporale;
presenta in certi casi anche instabilita'.
E comunque introduce un errore sistematico che cresce come il numero
di passi, e che puoi si' verificare come ti ha indicato Giorgio, ma
non correggere.
Se per es. ti venisse in mente di studiare il moto di un pianeta,
scopriresti con raccapriccio un'orbita "a spirale"...
Molto meglio il metodo delle differenze centrali, che in forma
travestita trovi descritto anche nella "fisica di Feynman".
Se no ci sono metodi piu' sofisticati, per es. il Runge-Kutta di 4^
ordine, che permette passi temporali assai piu' lunghi. Ma bisogna
trovare le formule, che pero' sono molto diffuse, oppure ricorrere
alle "Numerical Recipes".
Pero' se vuoi capire quello che fai, meglio programmare algoritmi che
puoi capire...
------------------------------
Elio Fabri
Dip. di Fisica - Univ. di Pisa
------------------------------


Se vuoi integrare le e. del moto per un sistema conservativo ti 
consiglio l' algoritmo di Verlet con le velocita'. E' semplicissimo:
dalle forze a t -> a(t)
x(t+dt) = x(t) + v(t) dt  + a(t) dt^2 / 2       [1]
vaux(t+dt) = v(t) + a(t) dt/2              
adesso si calcolano le forze a t+dt e quindi le accelerazioni, a(t+dt)
v(t+dt) = vaux(t+dt) + a(t+dt) dt/2
si avanza nel tempo e si riparte da [1].
E ha molti pregi nascosti. Per una derivazione dello stesso puoi dare 
un'  occhiata ad una pagina che ho preparato per il corso che tengo al 
primo anno di fisica ( 
www-dft.ts.infn.it/~pastore/DIDA/fisica/MNF/vverlet/node1.html
 ).
La conservazione dell' energia dipende dall' ampiezza del passo di 
integrazione. Ma se provi a vedere come si conserva il momento  o la 
quantita' di moto per un sistema isolato troverai una piacevole 
sorpresa... che lo rende superiore ai vari Runge-Kutta.
Nel caso di forze dipendenti dalla velocita', il metodo si puo' 
generalizzare solo se si tratta di forze lineari. Per dipendenze 
diverse, meglio usare altro.
Giorgio

 generalizzare solo se si tratta di forze lineari.
....io volevo provare a vedere gli effetti dell'attrito dell'aria su un 
proiettile. Ho letto che si puo' ritenere la forza di attrito dell'aria 
proporzionale al quadrato della velocita' (ovviamente di verso opposto). 
In tal caso, l'algoritmo che mi hai proposto funzionerebbe ancora?
Per quel che capisco, penso di no, giacche': 
1) il sistema non sarebbe piu' conservativo (attrito => non 
conservativita')
2) la forza dipenderebbe dalla velocita' (dal suo modulo al quadrato), e 
quindi cadrebbe anche la seconda ipotesi che hai detto.
Deduco male, o e' effettivamente cosi'?
Grazie per tutto!
Ciao,
Dan


E' cosi'. Il problema e' la dipendenza quadratica. Con una dipendenza 
lineare (valida solo a basse velocita' ) e' ancora possibile estendere 
l' algoritmo.
Per il caso di dipendenza quadratica (o piu'  generale),   se hai a che 
fare con pochi gradi di liberta',  un Runge-Kutta dovrebbe andare piu' 
 che bene. Per molti gradi di liberta'  (diciamo da una trentina in su') 
probabilmente i metodi predictor-corrector possono essere piu'  efficienti
Giorgio

Se vuoi ci sono degli appunti di fisica computazionale, del corso che si 
tiene a Lecce, puoi scaricarteli in formato .ps
http://www.fisica.unile.it/%7Emanca/calcolo.ps
La matematica è un po "formale" ma spero ti possa risultare utile!
--
Pasquale Galianni
-Studente di Fisica università di Lecce 


Probabilmente in questo modo fai in modo "empirico" quello che fanno i 
cosidetti metodi "adaptive" in cui il time step varia per garantire una 
data precisione di  integrazione (sono noti come metodi di Adam-Bashford 
in analisi numerica). Se si vuole integrare il moto su un'  orbita a 
fortissima eccentricita' sono indubbiamente  da preferire. Per il moto 
planetario  metodi simplettici come il Verlet con le velocita'  sono 
migliori.
Giorgio

 finito, cioe':
[...]
se sei interessato a problemi di questo tipo potresti dare un'occhiata al 
manuale del programma X-Star: 
http://www.schlitt.net/xstar/
Si tratta di una guida introduttiva alla risoluzione numerica del problema 
(classico) a N-corpi, con una analisi delle prestazioni di diversi 
algoritrmi ecc...
Lorenzo