#0 

31-07-2007 12:34:01

Nebu
Petit nouveau
Date d'inscription: 31-07-2007
Messages: 5

Bonjour,

Bon je pense pas que mon problème soit spécifique a irrlicht, mais etant donnée que mon problème apparait dans un code sous irrlicht, je poste ici.
Donc mon problème se situe sur un calcul qui me retourne une valeur avec une précision etrange.

Voila le code incriminé
J = J+((dayspeed/86400.0)/1000.0)*dTime;

J est un f64, ainsi que dayspeed
dTime est un u32

Mon problème est que J ne se met pas a jour, j'ai eu beau essayer, ressayer rien a faire
J est de l'ordre du million et la présicion est d'environs 10 chiffres apres la virgule (meme si 6 seraient suffisant)

La plus grosse bizzarerie se situe dans le fait que si je decompose mon calcul ainsi
        f64 temp = ((dayspeed/86400.0)/1000.0)*dTime;
        f64 temp2 = temp+J;
        printf("", temp+J);
        J = temp2;
Et bien J prend la bonne valeur.
Sans le printf...rien n'y fait, avec le printf...ca marche
Toute autre tentative a lamentablement échouée, et si j'insère la moindre ligne de code entre l'affectation temp2 et le printf, ca ne fonctionne plus...

Autre chose, si je desactive l'option /arch:SSE2 du compilo, ce code ne fonctionne plus.

Je pense que ce problème depasse largement mes compétences, et j'essaie de retourner google mais je ne sais meme pas par ou chercher car ce problème est d'un flou absolu pour moi...
Quelqu'un aurais une idée ?

Hors ligne


#1 

31-07-2007 18:42:39

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

Nebu :

J = J+((dayspeed/86400.0)/1000.0)*dTime;


ton probleme fait a mon avis référence a des soucis de méthode numérique,
comme tu le sais sans doute, en informatique on ne peut pas se permettre d'ecrire les formules mathématiques directement, parce que lorsqu'on joue avec des flottant, l'ordinateur est incapable de faire mieux que des approximations
a mon avis avec de si gros chiffres, tu fait un truc du style
J = J + Di 
avec Di tellement proche de zero que ca n'a pas de sens pour la machine

essayons de simplifier la formule parce que si tu l'écrit, chaque grosse opération de calcul va aggrandir la marge d'erreur

J = J + ( ( dayspeed / (86400.0*1000.0) )*dTime;

cette formule est mauvaise parce que la premiere division va générer une grosse marge d'erreur, et cette erreur va etre multipliée par dTime, pour ensuite faire une nouvelle grosse division (avec dayspeed) qui va faire exploser la marge d'erreur

J = J + dayspeed / ( dTime / 86400.0*1000.0 )

J= J + (dayspeed * dTime ) /  ( 86400000 )

voila qui est deja plus propre et qui perdra moins en précision lors du calcul
(j'espere que je me goure pas dans la formule, bon au moins c'est ca l'idée)

maintenant, tu doit trouver comment pouvoir diviser par moins que 86400000, parce que ca commence a faire un tres gros chiffre, meme pour un pc, pour moi une soluce ce serai :

J= J +  (  (dayspeed * dTime ) /  ( 864 )  )  * 10 ^ -5

la ton pc a deja plus de chance de s'en sortir
mais note que c'est quand meme idiot de diviser par 10^ 5, tu va perdre enormement en précision, autant stocker ton truc dans deux variables J et H

quand H atteint un certain seuil, tu incrémente J,
voila j'espere que ca va t'aider et que je suis pas hors sujet

tu peux donner un ordre de grandeur pour les valeurs de tes varibles dTimes et dayspeed ?
si tu m'explique ce tu veux calculer, je veux bien m'y pencher dessus

Nebu :

La plus grosse bizzarerie se situe dans le fait que si je decompose mon calcul ainsi
        f64 temp = ((dayspeed/86400.0)/1000.0)*dTime;
        f64 temp2 = temp+J;
        printf("", temp+J);
        J = temp2;
Et bien J prend la bonne valeur.
Sans le printf...rien n'y fait, avec le printf...ca marche
Toute autre tentative a lamentablement échouée, et si j'insère la moindre ligne de code entre l'affectation temp2 et le printf, ca ne fonctionne plus...


ca sent le débordement non maitrisé non ?

Nebu :

Autre chose, si je desactive l'option /arch:SSE2 du compilo, ce code ne fonctionne plus.


ne fonctionne plus ? ou ne compile plus ?

Dernière modification par Jerry Kan (31-07-2007 18:44:00)

Hors ligne


#2 

01-08-2007 08:02:58

Nebu
Petit nouveau
Date d'inscription: 31-07-2007
Messages: 5

Merci Jerry Kan pour ta réponse.
Je vais essayer de t'eclairer un peu sur ce problème.

Lorsque je fait ceci
f64 temp = ((dayspeed/86400.0)/1000.0)*dTime;
Et que j'affiche temp, j'ai bien la bonne valeur pour temp (qui est entre 0.005 et 0.007 avec plusieurs chiffres apres la virgule) comme je l'ai dit j'ai besoin d'une precision d'environs 6 a 10 chiffres apres la virgule.

Lorsque j'affiche J a son initialisation, son ordre de grandeur est du million avec 2 chiffres apres la virgule (je n'ai pas le code sous les yeux, donc je ne connais pas la valeur exact). Tout au long du déroulement, il ne dépassera pas l'ordre du million, et les 6 a 10 chiffres apres la virgule.

dTime est le différentiel en ms entre chaque frame.
dayspeed vaut 5000 et ne depassera jamais cette valeur.

Je perd la précision lorsque j'effectue l'addition J+temp.
Si j'affiche J apres cette addition, j'obtiens la valeur initiale de J
Et lorsque juste apres je fait le printf (qui comme tu l'as dit semble etre un débordement) J prend bien la valeur J+temp (exactement la bonne valeur a 10 chiffres apres la virgule pres)
Penses tu qu'un debordement permettrais d'obtenir le bon resultat au bon endroit dans la memoire oO?

Sinon lorsque je desactive l'option /arch:SSE2, le programme compile, mais le fait de faire le printf n'affecte pas la valeur correct a J

Par ailleurs, j'ai pensé a decomposer le calcul et le tourner autrement, ca n'as pas résolu mon pb vu que je perd la precision seulement lorsque j'addition temp a J. D'apres ce que tu m'as dit ce serais donc du au fait que J est tellement grand par rapport a temp que le proc le concidère égal a 0.
Connaitrais tu un moyen de savoir si le processeur effectue bel et bien cette approximation ? (faire le test temp == 0 marcherais peut etre ?)

De ce fait la premiere idée qui me viens a l'esprit serais donc de concerver dans un int la partie entiere de J et dans un double la partie décimale, d'effectuer mes calculs et lorsque ma partie décimale depasse 1, j'addition sa partie entiere a ma partie decimale. J'aurais donc une partie décimale qui ne vaudra pas plus de 1 a additionner a mon temp qui vaut entre 0.005 et 0.007 le calcul devrais etre OK.

Hors ligne


#3 

07-08-2007 12:37:08

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

Nebu :

Connaitrais tu un moyen de savoir si le processeur effectue bel et bien cette approximation ? (faire le test temp == 0 marcherais peut etre ?)


hm, je pense que lorsque l'on rentre dans ce genre de probleme, on est sur de se retrouver avec une solution complexe et pas portable, meme si tu trouve, ca ne sera pas stable

Nebu :

De ce fait la premiere idée qui me viens a l'esprit serais donc de concerver dans un int la partie entiere de J et dans un double la partie décimale, d'effectuer mes calculs et lorsque ma partie décimale depasse 1, j'addition sa partie entiere a ma partie decimale. J'aurais donc une partie décimale qui ne vaudra pas plus de 1 a additionner a mon temp qui vaut entre 0.005 et 0.007 le calcul devrais etre OK.


oui, je pense aussi que c'est une bonne idée, (regle du KISS smile )

Hors ligne


#4 

13-08-2007 17:39:16

Nebu
Petit nouveau
Date d'inscription: 31-07-2007
Messages: 5

Mon pb n'aurais t'il pas un rapport avec:
http://irrlicht.sourceforge.net/phpBB2/ … hp?t=23388

Je vais essayer ce que conseil vitek par curiosité

Edit: Impossible de ne pas poster et/ou d'editer en double

Dernière modification par Nebu (13-08-2007 17:40:25)

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
883 membres
1429 sujets
11121 messages
Dernier membre inscrit: Saidov17
118 invités en ligne
Aucun membre connecté
RSS Feed