Forum Clubic

C++ résidu de valeur dans des boucles

Bonjour,

Dans un programme en c++ que je compile avec DEV-C++, j’ai fais :



float debutX=-4;
float finX=4;
float pasX=0.8;
float debutY=-4;
float finY=4;
float pasY=0.8;

for(float c=debutX; c<=finX; c+=pasX)
   {
   for(float d=debutY; d<=finY; d+=pasY)
      {
      
      for(int e=0; e<tab_coo.size(); e++)
         {
         
         if(tab_coo[e].x==c) || (tab_coo[e].y==d)
            {
            cout << e << endl;
            }
         
         }
      }
   }

Mon problème est que quand c ou d sont sensé être egaux à zéro, j’ai des valeurs du style -1.19209e-007
D’où vient le problème ?
J’ai aussi eu la même chose dans le code suivant pour la valeur du cosinus avec angle_tmp=90 :


void Coordinate::rotation(float angle_tmp)
	{
	float pi=2*acos(0);
	
	float x_temp=this->x*cos(angle_tmp*pi/180)-this->y*sin(angle_tmp*pi/180);
	float y_temp=this->x*sin(angle_tmp*pi/180)+this->y*cos(angle_tmp*pi/180);
	
	this->x=x_temp;
	this->y=y_temp;
	}

Je me souviens d’une remarque de mes profs, en 3D, sur les flottants et “0” : faut jamais comparer en égalité avec les flottants, mais avec un epsilon, ie: x == c devient (c-e) <= x && x <= (c+e))

Essaye double au lieu de float, c’est plus précis.

Le problème vient du fait que 0.8 ne peut pas être exprimé avec un nombre fini de chiffres après la virgule en binaire (ça fait 0.11001100110011…), le CPU ne pourra jamais le représenter exactement, c’est comme 1/3 en décimal, il y aura toujours une légère erreur, surtout que float n’est pas très précis, tu devrais utiliser des double.
La solution est d’arrondir le résultat avec la précision qui te convient (entier, 1 décimale…)
Edité le 24/10/2011 à 14:09

Une autre astuce est de tout multiplier par 100 par exemple, comme ca tu n’utilise plus que des entier. Plus de problème pour les comparaisons.

C’est une solution, travailler en virgule fixe.
Mais ca ne marche pas pour son deuxième exemple.

De toute façon comme ça a été dit il faut éviter les égalités sur les flottants, uniquement les comparaisons d’infériorité ou de supériorité.
Edité le 08/11/2011 à 14:09

Ou faire un équivalent BigDecimal… mais bon, ensuite c’est sortir le canon pour tuer une mouche :slight_smile:

Bien sur que si, en admettant que x et y soient en virgule fixe (n’importe quel précision, ça changera juste la précision du résultat)

float const pi=2acos(0); // mettre la constante directement si on fait pas trop confiance au compilo
float cosfloat = cos(angle_tmp
pi/180); // à tabuler

short cosinus = __max(-32768, __min(32767, 32768cosfloat )); // à tabuler
short sinus = __max(-32768, __min(32767, 32768
sqrt(1 - cosfloat *cosfloat))); // à tabuler

x_temp = (this->x * cosinus - this->y * sinus) >> 15;
y_temp = (this->y * cosinus + this->x * sinus) >> 15;

this->x = x_temp;
this->y = y_temp;

Je te laisse évaluer le gain en temps d’exécution pour quasiment la même précision.
Edité le 21/11/2011 à 15:04