Visual C++ 6.0: drôle de bug avec des calculs sur des flottants !

Visual C++ 6.0: drôle de bug avec des calculs sur des flottants ! - Programmation

Marsh Posté le 29-10-2001 à 23:18:34    

voilà, j'ai un bug que je n'arrive pas à résoudre..
 
j'ai écrit une procédure qui permet pour un ensemble de sommets (vertices) contenant des coordonnées u,v de texture de faire une interpolation de ces coordonénes u,v vers de nouvelles coordonnées u,v définis par un autre tableau de vertices. Mes sommets sont stockés dans une table que je parcours avec une double boucle i,j linérairement. L'interpolation va en fait rapporcher la coordonnées courante tu ou tv (u,v texture) vers la prochaine coordonnées lui correspondante dans le tableau des nouvelles coordonées. Ce rapprochement se fait par un pas d'incrémentation défini par "inctrans" (un flottant) car les coordonnées u,v (tu et tv donc) varient entre 0.0f et 1.0f.
Le problème est le suivant: certaines coordonées u,v n'atteignent jamais leur valeur de destination, pourtant ma procédure me semble bonne. la voici:
 
"
int completed = 0;
 
for(int j = 0; j < StepMesh+1; j++) {
  for(int i = 0; i < StepMesh+1; i++) {
   if( (CurrentTrans[i + (j*(StepMesh+1))].tu + inctrans) < NextTrans[i + (j*(StepMesh+1))].tu)
    CurrentTrans[i + (j*(StepMesh+1))].tu += inctrans;
   else if( (CurrentTrans[i + (j*(StepMesh+1))].tu - inctrans) > NextTrans[i + (j*StepMesh+1)].tu)
    CurrentTrans[i + (j*(StepMesh+1))].tu -= inctrans;
   else { CurrentTrans[i + (j*(StepMesh+1))].tu = NextTrans[i + (j*(StepMesh+1))].tu; completed++; }
 
   if( (CurrentTrans[i + (j*(StepMesh+1))].tv + inctrans) < NextTrans[i + (j*(StepMesh+1))].tv)
    CurrentTrans[i + (j*(StepMesh+1))].tv += inctrans;
   else if( (CurrentTrans[i + (j*(StepMesh+1))].tv - inctrans) > NextTrans[i + (j*(StepMesh+1))].tv)
    CurrentTrans[i + (j*(StepMesh+1))].tv -= inctrans;
   else { CurrentTrans[i + (j*(StepMesh+1))].tv = NextTrans[i + (j*(StepMesh+1))].tv; completed++; }
  }
 }
"
 
la valeur "completed" contient à la fin le nombre de sommets dont l'interpolation est terminée X 2 (car deux coordonnées par sommets: tu et tv).
 
j'ai remarqué que pour un tableau de taille 2X2, l'erreur survient à la valeur 1,0.tu  (comprendre i= 1, j = 0, coordonnées tu)
 
l'erreur intervient toujours à cet endroit et aussi à d'autres quand le tableau est plus grand.  
J'ai en fait pû vérifier que lors du test "if( (CurrentTrans[i + (j*(StepMesh+1))].tu - inctrans) > NextTrans[i + (j*StepMesh+1)].tu)" le programme semble se tromper dans l'évaluation et entraine donc un mauvais résultat. Par exemple si CurrentTrans[i + (j*(StepMesh+1))].tu = 0.9858, que NextTrans[i + (j*StepMesh+1)].tu = 0.985 et que inctrans = 0.001 alors le compilateur va kan même soustraire inctrans à CurrentTrans[i + (j*(StepMesh+1))].tu et ainsi sa valeur (0.9848) va passer en dessous de celle de CurrentTrans[i + (j*(StepMesh+1))].tu, ce qui n'aurait jamais dû arriver !
à la boucle prochaine inctrans est encore décrémentée à CurrentTrans[i + (j*(StepMesh+1))].tu  (valant ainsi 0.9838 !!) et ce ne sera qu'à la boucle prochaine que sa valeur va être enfin augmenté (à 0.9848) puis rediminuer (à 0.9838) et ainsi de suite !! Je n'y comprend rien ! j'ai essayé de changer la routine en une autre similaire et dans ce cas les erreurs interviennent sur d'autres (i,j)...  
 
kk'un pourrait-il m'aider ?? merci d'avance pour ceux qui feront l'effort d'essayer de comprendre ;) (car je sais que je n'ai aps été très clair) !

 

[edtdd]--Message édité par ZZZzzz--[/edtdd]

Reply

Marsh Posté le 29-10-2001 à 23:18:34   

Reply

Marsh Posté le 29-10-2001 à 23:22:56    

desoler g pas trop envie de tous lire mais c juste pour te dire que tous les processeurs sont bugger sur les calculs flotants.
c du a une norme iso pour aller plus vite
je c que quand je faisait 0.000001*1000000 ou un truc dans le genre il me donner un resultat faux
 
ps: source: msdn library

 

[edtdd]--Message édité par TheJackal--[/edtdd]

Reply

Marsh Posté le 29-10-2001 à 23:36:44    

C'est pas clair du tout.
C'est quoi CurrentTrans et NextTrans ?

Reply

Marsh Posté le 29-10-2001 à 23:57:34    

je connait le pb d'imprecision des flottans mais dans mon cas ça m'étonnerai que ce soit ça (ou alors ya vraiment un blem d'utilité des flottants...)
 CurrentTrans et NextTrans sont les tableaux respectif contenant les sommets courants et suivants. Un sommet est uns structure défini par 3 coordonées dans l'espace (x,y et z) et par 2 coordonées pour la texture (tu et tv)... ce sont des sommets d'aobjets 3D en fait (bon je simplifie un peu là). StepMesh représente la dimension de mon tableau (tableau de dimension StepMesh+1 * StepMesh+1). J'espère que ça sera u peu plus clair (mais n'hésitez à demander des précisions kan même) !

 

[edtdd]--Message édité par ZZZzzz--[/edtdd]

Reply

Marsh Posté le 30-10-2001 à 00:22:51    

salut Z,
 
as-tu vérifié que tu avais désactivé l'option de compilateur fastmath (ele a peut-être un autre nom sous C++ 6.0. tjrs est-il que pour executé plus vite les flottant les compilateur intègrent des lib de calcul qui ne respecte pas completement le format IEEE, mais si je me rapelle bien dans certains cas l'erreur de précision peut devenir enorme.
 
Sinon essaie de voir si en jouant avec les options de compil ça change qquechose.

Reply

Marsh Posté le 30-10-2001 à 00:27:17    

pour ton code,
 
tu voudrais pas nous le réecrire avec des intentationn compelte et une variable a = i + (j*(StepMesh+1)). On y gagnerais en clarté.

Reply

Marsh Posté le 30-10-2001 à 00:33:16    

ça m'a plutôt l'air de venir du code en lui-même. tu itères avec une constante plutôt que de faire une interpolation linéaire. si tu avais codé des fades en 256 couleurs, tu verrais le problème :D : les valeurs sources les plus proches de celles de destination atteindront celles-ci plus vite, les autres mettront pas mal de temps -> le temps total pour faire l'interpolation est dépendant de tes données. traduit en fade noir->image, ça fait pas bô, les couleurs passent par le gris avant de se colorer.
 
donc, interpolation linéaire de a vers b : on fait varier un coeff de 0 à 1, v :
valeur interpolée : a*(1-v) + b*v (ou a + (b-a)*v)
 
donc, soit meshA et meshB les deux meshs, stepMesh la mesh interpolée, v le coeff d'interpolation (de 0 à 1)
 
stepMesh[i].tu = meshA[i].tu*(1-v) + meshB[i].tu*v
 
et vala ...

Reply

Marsh Posté le 30-10-2001 à 00:50:43    

youdon'tcare> je sais c pas un interpolation linéraire.. mas c voulu (en fait j'ai pas voulu me prendre la tête et je pense que finalement le fait que certaines valeurs arrivent à destination avant d'autres n'est pas plus mal. C pour cela qu'il y a une varaible "completed"... et puis cela n'explique pas le mauvais fonctionnement de ma procédure non ?
 
barballera> je vais regarder pour les options, sinon pour mon code je pense pas que remplacer Trans[...] par a clarifie grand chose puisque je dois garder Trans[...] pour les affectations. Je pense qu'un copier-coller dans un fichier .txt devrait déjà rendre les choses plus lisibles ;) !

Reply

Marsh Posté le 30-10-2001 à 00:51:54    

barbarella> en y repensant je compile actuellement en mode debug, donc ya pas d'optimisation et à fortiori pas d'option /fastmath (j'ai vérifié j'ai pas vu de choses semblables)

Reply

Marsh Posté le 30-10-2001 à 08:42:17    

slt,
 
tes flottants sont en précision single ? si oui, quand tu passes a double ça change qque chose ?

Reply

Marsh Posté le 30-10-2001 à 08:42:17   

Reply

Marsh Posté le 30-10-2001 à 11:07:27    

le pb c que la structure d'un sommet n'est défini qu'avec es flottans simple précision. Je ne peux pas les passer en double. je peux faire les calculs (et inctrans) en double mais je doute que ça ne change kkchose au résultat. je vais kan même essayer.

Reply

Marsh Posté le 30-10-2001 à 11:11:26    

non, ça ne change rien ...

Reply

Marsh Posté le 30-10-2001 à 11:21:23    

slt,
 
de toute façon il n'y pas 36 solutions. Si ton algo est bon, alors c'est le compilateur qui se mélange les pinceaux. Lorsque ça m'arrive, je réécris l'algo d'une autre façon. Généralement je tente :
 
1 - de simplifier les expressions pour simplifier la vie du compilateur, d'ou l'idée du a = ...  
 
2 - je décompose plus l'algo, quand c'est possible.
 
sinon je ne vois pas comment d'aider plus, hormis vérifier les déclaration de tes variables et leur initialisation. Récement j'ai fait un cauchemar, j'assimilais tous les long a des unsigned int :D, et je modifiais des dizaines de millier de lignes pour remplacer les long par des int, pour un prog qui doit tourner sur des microprocesseur IA-32 je te raconte pas de l'interet :D

Reply

Marsh Posté le 30-10-2001 à 11:33:52    

:D pas marrant en effet ...  
bon bah merci Barbarella, je vais essayer de l'écrire autrement (je l'avais déjà fait mais peut-être pas assez différent). Il est apparement clair que c le compilo qui s'embrouille car je viens de tester l'algo sur un prog à part (qui ne fait que ça) et j'ai la même erreur... ça ne viens donc pas de pb d'allocations mémoire...

Reply

Marsh Posté le 30-10-2001 à 11:34:37    

ok,
 
je viens de refaire l'intentation de ton algo chez moi et j'ai remplacé tous tes i + j*(StepMesh+1)) par une variable a. devinnes ce que j'ai trouvé, ca !
 
i + (j*StepMesh+1)
 
or je suppose que ça devrait être i + (j*(StepMesh+1)) a cause de l'ordre des opérateurs. La mul j*StepMesh sera faite avant le StepMesh+1.
 
voir :if( (CurrentTrans[i + (j*(StepMesh+1))].tu - inctrans) > NextTrans[i + (j*StepMesh+1)].tu)  
 
 
Si c'est ça, de grace travaille la lisibilité de tes prog ;)

 

[edtdd]--Message édité par barbarella--[/edtdd]

Reply

Marsh Posté le 30-10-2001 à 11:42:01    

encre merci !  
j'ai simplement fait comme tu as dis (j'ai stocké mes valeurs de tab dans des variables) et c apparement suffisant pour corriger le pb ;) !!
 
drôle de bug kan même :mouais: ...

Reply

Marsh Posté le 30-10-2001 à 11:45:30    

ouais,
 
donc le bogue était bien le i + (j*StepMesh+1) en faisant a =i + (j*(StepMesh+1)) tu l'as implicitement corrigé

Reply

Marsh Posté le 30-10-2001 à 19:18:21    

non car en fait voilà ce n'est pas ça que j'a imodifié. J'ai directement stocké la valeur de Trans[...].tu et NextTran[].tu dans des variables.
 
voilà la modif qui fonctionne:
 
"
for(int j = 0; j < StepMesh+1; j++) {
  for(int i = 0; i < StepMesh+1; i++) {
 u = CurrentTrans[i + (j*(StepMesh+1))].tu;
 v = CurrentTrans[i + (j*(StepMesh+1))].tv;
 nu = NextTrans[i + (j*(StepMesh+1))].tu;
 nv = NextTrans[i + (j*(StepMesh+1))].tv;
     
 if( (u + inctrans) < nu)
     CurrentTrans[i + (j*(StepMesh+1))].tu += inctrans;
 else if( (u - inctrans) > nu)
   CurrentTrans[i + (j*(StepMesh+1))].tu -= inctrans;
 else  
          { CurrentTrans[i + (j*(StepMesh+1))].tu = nu; completed++; }
 
 
 if( (v + inctrans) < nv)
   CurrentTrans[i + (j*(StepMesh+1))].tv += inctrans;
 else if( (v - inctrans) > nv)
   CurrentTrans[i + (j*(StepMesh+1))].tv -= inctrans;
 else
          { CurrentTrans[i + (j*(StepMesh+1))].tv = nv; completed++; }
 
}
}
"
 
à vrai dire je vois pas ce que ça change dans l'algo, mais maintenant ça fonctionne :) !!

Reply

Marsh Posté le 30-10-2001 à 19:26:13    

je viens de me rendre compte que ma réponse ne contredit pas la tienne, cependant je comprend pas pourquoi il y aurait eu un bug au niveau de i + (j*StepMesh + 1) ... et les résultats étaient vraiment bizarres... le bug avait lieu quand i >= (j-2)mod(StepMesh) ou un truc du genre :??: ...

Reply

Marsh Posté le 30-10-2001 à 19:36:34    

Z,
 
une expression du genre (A*B+1) <> (A*(B+1)) c'est a cause de l'ordre de priorité des opérateurs. La multiplication passe avant l'addition. Remarque dans ce cas c'est encore plus simple, le compilateur voit la multiplication avant l'addition.
 
Tu devais obtenir un résultat bizarre avec ton (j*StepMesh + 1)  
 
je suis sur que si tu reprenais la fonction que tu as donné en début de topic juste en corrigeant le (j*StepMesh + 1) en (j*(StepMesh + 1)) ça marcherait.
 
 
Sinon le jour ou t'auras besoin d'optimisation viens nous voir car je crois qu'on pourra te donner quelques conseils.  
 
---------------------------
L'optimisation n'est pas une technique mais un état d'esprit ;)

Reply

Marsh Posté le 15-11-2001 à 21:07:47    

barbarella> où vois-tu dans ma fonction de départ un " (j*StepMesh + 1)" ? j'ai bien fait attention à mettre " (j* (StepMesh + 1) )" ...
par ailleurs je cherche évidemment à optimiser mes programmes mais en ce qui concerne cet algo cété juste un essai et "StepMesh" restait relativement faible donc ce n'est pas grave s'il elle n'est pas bien optimisé .

Reply

Marsh Posté le 15-11-2001 à 21:39:37    

salut,
 
dans le code que tu nous as donné en début de post  
 
int completed = 0;  
 
for(int j = 0; j < StepMesh+1; j++) {  
 for(int i = 0; i < StepMesh+1; i++) {  
  if( (CurrentTrans[i + (j*(StepMesh+1))].tu + inctrans) < NextTrans[i + (j*(StepMesh+1))].tu)  
   CurrentTrans[i + (j*(StepMesh+1))].tu += inctrans;  
  else if( (CurrentTrans[i + (j*(StepMesh+1))].tu - inctrans) > NextTrans[i + (j*StepMesh+1)].tu)  
   CurrentTrans[i + (j*(StepMesh+1))].tu -= inctrans;  
  else { CurrentTrans[i + (j*(StepMesh+1))].tu = NextTrans[i + (j*(StepMesh+1))].tu; completed++; }  
 
  if( (CurrentTrans[i + (j*(StepMesh+1))].tv + inctrans) < NextTrans[i + (j*(StepMesh+1))].tv)  
   CurrentTrans[i + (j*(StepMesh+1))].tv += inctrans;  
  else if( (CurrentTrans[i + (j*(StepMesh+1))].tv - inctrans) > NextTrans[i + (j*(StepMesh+1))].tv)  
   CurrentTrans[i + (j*(StepMesh+1))].tv -= inctrans;  
  else { CurrentTrans[i + (j*(StepMesh+1))].tv = NextTrans[i + (j*(StepMesh+1))].tv; completed++; }  
 }  
}  
 
 
j'ai mis en gras souligné le méchant vilain canard ;)

 

[edtdd]--Message édité par barbarella--[/edtdd]

Reply

Marsh Posté le 16-11-2001 à 13:07:26    

arf mais tu as raison !! javé po vu :( !!!!
ben voilà cété ça la cause du bug, quel con vraiment... et moi qui suspectait encore le compilateur, chui vraiment nul !!

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed