Newsgroup: it.comp.lang.c++
Titolo: definire precisioine nel duoble

Salve ragazzi,
sto manipolando un array di double per indicizzare alcune ricerche
velocizzate su stringhe,
ho bisogno di valori precisi, non approssimativi, perciò vi chiedo un
parere,
ho letto nei post precedenti che il double arriva con precisione fino
a 15 cifre decimali, oltre fa approssimazioni,
la cosa strana è che quando chiedo di visualizzarmi attraverso la
classe
    CString str;
la variabile
    double indice;
con questa sintassi
    str.Format("%6.80f",indice);
mi visualizza tutto il numero lungo 86 cifre e dice che può allungarsi
ancora...
qualcuno sa qual'è il limite dei decimali dopo la virgola con una
definizione precisa?
non so se sto facendo giusto, la precisione la trovo con la seguente
funzione:
1) chiedo se il valore double si può considerare preciso
char LimiteDouble(){ return (indice/2) ? indice == ( (indice/2)*2 ) ?
1 : 0  : 0 ; }
2) dimezzo il valore e successivamente ripeto la funzione precedente
void Dimezza(){ indice/=2; }
sto sbagliando?
mi risulterà sempre un valore preciso con questa procedura?
duido

 1) chiedo se il valore double si può considerare preciso
Dipende da cosa intendi per preciso !
per esempio la rappresentazione in double di 0.3 (3 decimi) non e' precisa.
Questo per il semplice motivo che la rappresentazione in binario
di 3/10 e' un numero binario periodico, quindi quando tronchi questa 
rappresentazione (per ficcarla in un double) non puoi non commettere
un errore.
Per esempio se tronchi la rappresentazione di 0.3 a 25 bit dopo
la virgola, hai
0.0100110011001100110011001 che riconvertito in decimale e' esattamente
0.2999999821186065673828125 cioe' un po' meno di 0.3
I double a 8 byte di solito usano 52 o 53 bit (non ricordo)
per la mantissa e gli altri per l'esponente (sempre in binario).
Quindi rappresentano i numeri con una precisione relativa di
circa 1/(2^52) cioe' circa 4*10^15. Questo grosso modo vuol
dire che ti puoi aspettare che il tuo numero decimale abbia
circa 15 cifre significative esatte. Attenzione che queste cifre
significative comprendono sia la parte prima della virgola che
quella dopo. cioe' le cifre significative di 1234.56 e 1.23456 sono
le stesse.
Gli unici numeri che puoi rappresentare precisamente
con un double sono somme di potenze di 2 (potenze positive e negative),
entro un certo range. Per esempio con un double puoi rappresentare
"precisamente" il valore 4+1+1/8+1/512 = 5.1269531250000.
Ma, siccome il numero di bit a tua disposizione per la mantissa e' una 
cinquantina (un po'di piu' per i double a 10 bytes) non puoi 
rappresentare esattamente 2^37+1+1/(2^88) anche se e' un numero con
appena 3 bit diversi da 0.
ciao,
g.

...

prova ad includere <limits> e dare un'occhiata alla classe:
numeric_limits<T>, fa parte della libreria standard c++.
ci sono membri e funzioni  interessanti come:
numeric_limits<double>::min();
numeric_limits<double>::digits;
per vedere i parametri della tua macchina.
la precisione (dei double) penso che tu possa vederla con:
numeric_limits<double>::epsilon();
epsilon e'il numero piu piccolo rappresentabile, cioe' tale che:
1-epsilon+1 
da un risultato diverso da zero
ciao

Qualcuno sa come poter verificare se dividendo un valore double la
risultante è un valore approssimato oppure preciso?
grazie duido

 risultante è un valore approssimato oppure preciso?
moltiplichi il risultato per il divisore e lo confronti con il dividendo.
Ciao,
Nicola


Se il bit meno significativo di un double e' 1 allora la divisione
non sara' corretta (ma in termini di errore relativo avremo un
errore inferiore a 10^(-15),
che per la maggior parte delle applicazioni e' ragionevole.)
in teoria puoi verificare scrivendo
a=x/2;
if (a*2==x) etc.etc.
oppure puoi andare a testare direttamente il bit,
se sai come sono rappresentati i numeri.
pero' tieni conto che i floating point sono bastardi.
Per esempio mi e' capitato di scrivere un programma
nel quale due valori x e y venivano calcolati in
due punti diversi del programma usando le stesse operazioni
sugli stessi operandi.
Tuttavia, il compilatore per motivi di ottimizzazione
aveva cambiato l'ordine di esecuzione delle operazioni,
e quindi alla fine x e y erano diversi (di poco, ovviamente,
ma quanto bastava a rendere falsa la condizione (x==y).
Questo per dirti che se i tuoi numeri sono il risultato
di operazioni tra numeri in floating point, allora
porsi domande sul bit meno significativo potrebbe essere
inutile.
Scusa la presunzione, ma se hai questi problemi con i double
allora forse non sono il tipo di dato adatto a quello che stai
cercando di fare, o forse dovresti studiare in dettaglio come vengono
rappresentati nella memoria del calcolatore.
forse usando i long o gli interi a 64 bit che
saranno comunque disponibili sul tuo sistema riesci a fare le stesse
cose con meno problemi ?
ciao,
g.

 parere,
Se ti servono come indici, perche' usi un tipo a virgola mobile? Non
sarebbe meglio utilizzare un tipo intero? Tra l'altro su Windows
esiste il tipo __int64 che e' rappresentato su 8 byte proprio come il
double.
Ciao,
Nicola

 grazie duido
giovanni ti ha spiegato approfonditamente come le macchine
rappresentano i numeri.
generalizzando si puo'dire che ogni operazione all'interno della tua
macchina crea un'approssimazione (che se non sbaglio si chiama
roundoff error).
questi errori tendono ad accumularsi con operazioni successive
(nell'ordine di epsilon*sqrt(N), N e'il numero di operazioni; nei casi
peggiori l'errore puo' diventare epsilon*N)  ed e' questa la ragione
per cui si sceglie di usare  (almeno quando la precisione e'
importante) una rappresentazione in  doppia precisione.
se hai a che fare con numeri float puoi dimenticare l'aritmetica
esatta.

ringrazio tutti quanti per le dritte e credo che seguirņ il consiglio
di non incasinarmi sui double e portarmi sui long.
grazie ancora duido