PDA

View Full Version : [c/c++]Precisione double


shinya
05-01-2006, 11:59
Ciao a tutti!
Devo dividere una variabile double per 2 ad ogni iterazione e capire quando fermarmi (cioè quando esco dallo spazio dei numeri rappresentabili). Esiste una maniera portabile di farlo?

Ho provato:


#include <iostream>

int main(int argc, char **argv)
{
long double x = 2.0;
while(1) {
std::cout << x << std::endl;
x /= 2;
}
return 0;
}


e ad un certo punto la 'x' diventa '0'. Solo che se testo questa condizione non succede nulla (cioè se aggiungo un if (0 == x) break; in quel pezzettino di while).
Qualcuno sa come si fa?

ps. il mio problema (più ampio) è di dover zoomare su un frattale fino alla massima precisione consentita dal double, quindi devo sapere quando si va oltre tale precisione.

ilsensine
05-01-2006, 12:17
A me il tuo codice funziona, ma il confronto di eguaglianza tra due double può generare problemi strani per via delle rappresentazioni/approssimazioni.

Prova così:

#include <iostream>

int main(int argc, char **argv)
{
long double x = 2.0;
long double x_2 = x/2.0;
while(x!=x_2) {
x = x_2;
x_2 /= 2.0;
std::cout << x << std::endl;
}
return 0;
}

shinya
05-01-2006, 12:50
Ho provato la tua variazione, ma dà lo stesso comportamento. Non si ferma mai.
In effetti quello è un test che dati perturbazioni dovute all'errore di macchina potrebbe dare risultati inattesi.
Sto pensando che, siccome la divisione parte sempre da 2.0 (perchè il frattale di mandelbrot è mappato su uno spazio complesso che va da (-2, -2) a (2, 2) all'inizio), posso ricercare l'ultimo valore sensato, che da me è 4.94066e-324 e fare un test su quello...quando lo raggiunge, stop.

Il problema è che quel numero è sensato sulla mia macchina, ma probabilmente non su altre.
Che ne dici? Non c'è una specie di INT_MAX del C per i double??

Cmq grazie della risposta :)

hombre
05-01-2006, 13:55
Dovresiti risolvere mettendo il controllo come " if (x>= 0 && x <= 0.1) "

hombre
05-01-2006, 14:30
Se poi devi confrontare due variabili in virgola mobile allora devi fare:
V3 = V1-V2 dove V3 è la differenza tra le due variabili V1 e V2 e poi devi confrontare così " if (V3 >= - 0.1 && V3 <= 0.1) " dove -0.1/0.1 è un range di tollerabilità.
Ou revoir!!!

shinya
05-01-2006, 15:15
Trovato! La classe numeric_limits è venuta in soccorso! Per chi fosse interessato, ecco la soluzione elegante :)


#include <iostream>
#include <limits>

int main(int argc, char **argv)
{
long double x = 2.0;
long double limit = std::numeric_limits<long double>::min();
while(x >= limit) {
std::cout << x << std::endl;
x /= 2.0;
}
return 0;
}

hombre
05-01-2006, 15:35
Trovato! La classe numeric_limits è venuta in soccorso! Per chi fosse interessato, ecco la soluzione elegante :)

Si in questo caso va bene, ma ti avevo postato l'altra soluzione per due motivi:
1) E' utilizzabile anche scrivendo codice in C;
2) E' utilizzabile anche quando non devi per forza iterare fino a zero o confrontare con zero, ma devi semplicemente confrontare un valore in virgola mobile con un altro.
Comunque in generale la regola di confronto tra valori in virgola mobile è confrontare un valore con un range di due valori.

Au revoir!