incompréhension du fonctionnemnent des nombres flottants

incompréhension du fonctionnemnent des nombres flottants - C++ - Programmation

Marsh Posté le 05-10-2003 à 15:53:00    

Voilà,
J'ai un drôle de problème avec mes variables double :
 
Qd j'effectue cette opération : dSolde -= RepasRecord->r_Prix et que les deux variables double ont la même valeur, que le résultat final me donne -2.2204460492503131e-016 aulieu de 0.00.. (5-=5 = 0).
Cela ne se passe que qd les deux variables ont la même valeur et pour l'instant j'utilise une astuce mais c'est pas très beau.
 

Code :
  1. if((dSolde - RepasRecord->r_Prix) == .0)
  2. dSolde = .0;
  3. else
  4. dSolde -= RepasRecord->r_Prix;


 
Des idées ?
 
Edit: tout compte fait, l'astuce ne fonctionne pas  :cry:


Message édité par iS@mi le 05-10-2003 à 15:57:21
Reply

Marsh Posté le 05-10-2003 à 15:53:00   

Reply

Marsh Posté le 05-10-2003 à 16:13:41    

Il ne faut jamais faire de tests d'égalité avec des nombres flottants car tu as toujours un pb de précision.
A la place, il faut que tu fasse une comparaison du genre :
if ( (a - b) < 1.0e-16 )
c'est-à-dire que tu spécifie la marge d'erreur que tu acceptes

Reply

Marsh Posté le 05-10-2003 à 16:21:58    

Enidan a écrit :

Il ne faut jamais faire de tests d'égalité avec des nombres flottants car tu as toujours un pb de précision.
A la place, il faut que tu fasse une comparaison du genre :
if ( (a - b) < 1.0e-16 )
c'est-à-dire que tu spécifie la marge d'erreur que tu acceptes


 :heink:  
Depuis quand des flottants ne peuvent pas être égaux?


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 05-10-2003 à 16:28:32    

Enidan a écrit :

Il ne faut jamais faire de tests d'égalité avec des nombres flottants car tu as toujours un pb de précision.
A la place, il faut que tu fasse une comparaison du genre :
if ( (a - b) < 1.0e-16 )
c'est-à-dire que tu spécifie la marge d'erreur que tu acceptes


 
J'imagine que mon problème est dû à la précision de mes nombres flotants ?
 
En fait il ne fait pas (3.25-3.25)
mais (3.249999999999... - 3.249999999999...), ce qui donne un truc 0.0000000000000000000000000000000000000000000000....1
Le double n'étant pas assez précis, il me retourne 2.2204460492503131e-016 ?
 
 

Reply

Marsh Posté le 05-10-2003 à 16:29:24    

c'est ça

Reply

Marsh Posté le 05-10-2003 à 16:29:39    

enfin pas vraiment un problème de précision

Reply

Marsh Posté le 05-10-2003 à 16:31:20    


lu, compris et je m'auto-flagelle...mais c'est quand même très moche! :pt1cable:


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 05-10-2003 à 17:39:11    

J'ai crié victoire trop tôt:
 
 
Voilà, le problème est que ma soustraction peut également donner comme résultat un nombre négatif et que dans le cas de if ( (a - b) < 1.0e-16 ) tous mes nombres négatifs seront définis à zéro ce qui n'est pas acceptable pour mon programme.
 
Je travaille avec des Euro, donc la précision serait de l'ordre des centièmes.
 
J'utilise ceci en attendant mais c'est à mon avis pas conseillé :  
if ( (a - b) == -2.2204460492503131e-016 )
 
J'ai également essayé if(((a - b) < 0.999) && ((a - b) > -0.999) mais comme le résultat de ma soustraction est -2.2204460492503131e-016 ca ne fonctionne pas.
 
Auriez-vous une astuce fiable pour savoir si le résultat de ma soustration est égual à zéro tip top ?
 
PS: Note, je peux aussi tout convertir en char* et définir ma valeur comme étant zéro si mon string est égual à "-0.00" mais bon c'est vachement bricoleur du dimanche ca  :lol:
 
Edit: je pense avoir trouvé la solution ici :
http://msdn.microsoft.com/library/ [...] cision.asp
Je vous tiens au courant.


Message édité par iS@mi le 05-10-2003 à 17:43:04
Reply

Marsh Posté le 05-10-2003 à 17:41:25    

?
 
if (fabs(a-b)<EPSILON)
{
...
}
 
 
pis tu te debrouilles trouver l'epsilon qui te convient
 
 

Reply

Marsh Posté le 05-10-2003 à 17:41:25   

Reply

Marsh Posté le 05-10-2003 à 17:47:38    

Voilà, ca marche (qu'est ce qu'on deviendrait sans MSDN).
 
 

Code :
  1. #define EPSILON 0.0001   // Define your own tolerance
  2. #define FLOAT_EQ(x,v) (((v - EPSILON) < x) && (x <( v + EPSILON)))
  3. if (FLOAT_EQ((dSolde - RepasRecord->r_Prix), 0.0000))
  4.    dSolde  = .0;

Reply

Marsh Posté le 05-10-2003 à 17:47:59    

grilled :/


---------------
L'ingénieur chipset nortiaux : Une iFricandelle svp ! "Spa du pâté, hin!" ©®Janfynette | "La plus grosse collec vivante de bans abusifs sur pattes" | OCCT v12 OUT !
Reply

Marsh Posté le 05-10-2003 à 17:55:02    

la solution de chrisbk est plus économique en principe (le fabs est simple alors qu'une comparaison en plus est coûteuse)

Reply

Marsh Posté le 05-10-2003 à 17:58:30    

d'ailleurs, pour un flottant, le fabs c'est pas un bit a changer uniquement ?


---------------
L'ingénieur chipset nortiaux : Une iFricandelle svp ! "Spa du pâté, hin!" ©®Janfynette | "La plus grosse collec vivante de bans abusifs sur pattes" | OCCT v12 OUT !
Reply

Marsh Posté le 05-10-2003 à 18:04:45    

tetedeiench a écrit :

d'ailleurs, pour un flottant, le fabs c'est pas un bit a changer uniquement ?


 
ben si  
 
float roger = -1;
 
(*((DWORD *)&roger)) & 7FFFFFFF
 
([:ciler])

Reply

Marsh Posté le 05-10-2003 à 18:05:11    

personne pour faire une jolie classe autour de tout ça ?

Reply

Marsh Posté le 05-10-2003 à 18:15:36    

Euh non, on me descendrait ma classe car "elle est pas Taz-compliant" :D
 
nan je deconne, je suis une bite monstrueuse en C++, je bidouille de facon laide, c'est tout.


---------------
L'ingénieur chipset nortiaux : Une iFricandelle svp ! "Spa du pâté, hin!" ©®Janfynette | "La plus grosse collec vivante de bans abusifs sur pattes" | OCCT v12 OUT !
Reply

Marsh Posté le 05-10-2003 à 18:27:02    

Code :
  1. const long double EPSILON=0.0001;
  2. template<typename T>
  3. inline bool Equal(const T &a, const T &b)
  4. {
  5. return ((a - EPSILON) < b) && (b <( a + EPSILON));
  6. }


 
ou alors on pousse avec mieux
 
 

Code :
  1. template<typename T>
  2. struct Equal
  3. {
  4. const T Epsilon;
  5. explicit Equal(const T &e) : Epsilon(e) {}
  6. bool operator()(const T &a, const T &b) const
  7. {
  8.    return ((a - Epsilon) < b) && (b <( a + Epsilon));
  9. }
  10. };


 
 
edit  je suis bête
 
j'avais écris initialement  
 
   /* ou la version avec fabs, gaffe, assurez vous d'avoir une fonction qui utilise le bon type fabs fonctionne avec les double
  rendez vous avec <tgmath.h> du C99 pour en savoir plus (le C++ planche dessus) */
 
mais Recherche En Cours


Message édité par Taz le 05-10-2003 à 18:51:28
Reply

Marsh Posté le 05-10-2003 à 18:59:51    

:o
 
Je savais pas qu'il pouvait y avir des soucis avec fabs :o


---------------
L'ingénieur chipset nortiaux : Une iFricandelle svp ! "Spa du pâté, hin!" ©®Janfynette | "La plus grosse collec vivante de bans abusifs sur pattes" | OCCT v12 OUT !
Reply

Marsh Posté le 05-10-2003 à 19:05:18    

plus de précision bientot
 
en C++, C89
double fabs(double)
int abs(int)
long int labs(long int);
 
d'ou le problème dans notre cas

Reply

Marsh Posté le 05-10-2003 à 19:07:55    

?
 
Ben ou ca l'problème :??: ( désolé d'être boulay )


---------------
L'ingénieur chipset nortiaux : Une iFricandelle svp ! "Spa du pâté, hin!" ©®Janfynette | "La plus grosse collec vivante de bans abusifs sur pattes" | OCCT v12 OUT !
Reply

Marsh Posté le 05-10-2003 à 19:08:37    

avec les long double on est foutu.

Reply

Marsh Posté le 05-10-2003 à 19:11:58    

ah vi bien vu :o


---------------
L'ingénieur chipset nortiaux : Une iFricandelle svp ! "Spa du pâté, hin!" ©®Janfynette | "La plus grosse collec vivante de bans abusifs sur pattes" | OCCT v12 OUT !
Reply

Marsh Posté le 05-10-2003 à 19:34:00    

Sinon que veux dire EPSILON ?
 
Je n'en ai jamais entendu parler (ca fait base spacial startrek  :D).
 

Reply

Marsh Posté le 05-10-2003 à 19:40:47    

bah rien c une lettre grecque
generalement on s'en sert pour decrire une petite valeur

Reply

Marsh Posté le 05-10-2003 à 20:02:46    

par ce que c'est la plus petite &#949;
 
bug  :o


Message édité par Taz le 05-10-2003 à 20:03:44
Reply

Marsh Posté le 05-10-2003 à 20:04:49    

iS@mi a écrit :

Voilà, ca marche (qu'est ce qu'on deviendrait sans MSDN).
 
 

Code :
  1. #define EPSILON 0.0001   // Define your own tolerance
  2. #define FLOAT_EQ(x,v) (((v - EPSILON) < x) && (x <( v + EPSILON)))
  3. if (FLOAT_EQ((dSolde - RepasRecord->r_Prix), 0.0000))
  4.    dSolde  = .0;




Surement grillé par la suite, mais euh

Code :
  1. FLOAT_EQ((dSolde - RepasRecord->r_Prix), 0.0000)


 
serait quand même mieux en  

Code :
  1. FLOAT_EQ(dSolde, RepasRecord->r_Prix)


non?


Message édité par skeye le 05-10-2003 à 20:05:05

---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 05-10-2003 à 20:14:41    

les macros ça pue, je suis à deux doigts de censurer :o

Reply

Marsh Posté le 05-10-2003 à 20:18:55    

Taz a écrit :

les macros ça pue, je suis à deux doigts de censurer :o


Ce serait de l'abus de pouvoir! :o


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 05-10-2003 à 20:19:57    

skeye a écrit :


Ce serait de l'abus de pouvoir! :o

modofacho  :o

Reply

Marsh Posté le 05-10-2003 à 20:20:57    

Taz a écrit :

modofacho  :o  


Te prends pas pour Harko hein!:o
...et on dévie du sujet là! :o


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 05-10-2003 à 20:23:46    

skeye a écrit :


Surement grillé par la suite, mais euh

Code :
  1. FLOAT_EQ((dSolde - RepasRecord->r_Prix), 0.0000)


 
serait quand même mieux en  

Code :
  1. FLOAT_EQ(dSolde, RepasRecord->r_Prix)


non?


 
Non, je vérifie juste si le résultat de la soustraction (dSolde - RepasRecord) est égale à zéro.
Si oui, je dis que dSolde est = 0.0 dans ces cas là.
 
Sinon Taz, pas ma faute si Microsoft met des Macro pour leur fonctions  :D  
J'utilise que des templates inline.


Message édité par iS@mi le 05-10-2003 à 20:24:49
Reply

Marsh Posté le 05-10-2003 à 20:24:32    

>Non, je vérifie juste si le résultat de la soustraction (dSolde - >RepasRecord) est égual à zéro.
>Si oui, je dis que dSolde est = .0 dans ces cas là.  
 
 
ce qui revient a tester l'egalité
 
edit : la reponse rapide, ou comment faire des quotes ignobles


Message édité par chrisbk le 05-10-2003 à 20:26:25
Reply

Marsh Posté le 05-10-2003 à 20:28:55    

chrisbk a écrit :

>Non, je vérifie juste si le résultat de la soustraction (dSolde - >RepasRecord) est égual à zéro.
>Si oui, je dis que dSolde est = .0 dans ces cas là.  
 
 
ce qui revient a tester l'egalité  


 
Heu oui ???
Comme 0.2499999-0.2499999 ne me retourne pas zéro tip top mais -2.2204460492503131e-016, j'utilise la fonction Equal pour savoir si ma soustraction de mes double donne bien 0.00.
 
Si oui, je dis que dSolde est = 0.0.
 
 if((a-b) == 0.0)
   a = 0.0;
 else
   a -= b;


Message édité par iS@mi le 05-10-2003 à 20:31:08
Reply

Marsh Posté le 05-10-2003 à 20:30:57    

[:humanrage]

Reply

Marsh Posté le 05-10-2003 à 20:35:22    


 
Tu ne vois pas ???
 
Si l'utilisateur de mon programme supprime un repas de la liste, je dois soustraire du solde, le prix de ce repas.
 
Si maintenant il s'avère que le solde est du même montant que le prix du repas, après soustraction, le solde sera à zéro mais la soustraction des double n'est pas parfaite, donc j'utilise le stratège (ex. : solde(25.10), PrixRepas(25.10), Solde-=PrixRepas = 0.00).
 

Code :
  1. if((solde-PrixRepas) == 0.0)
  2.   solde = 0.0; // L'astuce pour éviter d'avoir-2.2204460492503131e-016  
  3. else
  4.   solde -= PrixRepas; // rien à signaler, on soustrait normalement


Message édité par iS@mi le 05-10-2003 à 20:37:09
Reply

Marsh Posté le 05-10-2003 à 20:37:08    

merci j'avais compris :D
le point important de ta phrase est :
 
"si maintenant il s'avère que le solde est du même montant que le prix du repas"
 
donc tu peux tester l'egalité au lieu de faire une soustraction et de tester sur 0, c ce que voulais dire skeye

Reply

Marsh Posté le 05-10-2003 à 20:39:38    

note finalement, en virgule fixe t'aurais pas eu tous ces problemes [:meganne]

Reply

Marsh Posté le 05-10-2003 à 20:40:18    

chrisbk a écrit :

merci j'avais compris :D
le point important de ta phrase est :
 
"si maintenant il s'avère que le solde est du même montant que le prix du repas"
 
donc tu peux tester l'egalité au lieu de faire une soustraction et de tester sur 0, c ce que voulais dire skeye


 
Ha zuste  :lol:  :)  
C'est vrai, que c'est mieux aussi, toutes mes zescuses.

Reply

Marsh Posté le 05-10-2003 à 20:41:55    

faisez bien attention que
 

Code :
  1. float a;
  2. // ...
  3. a==0.0;
  4. a==0.0f;


 
sont deux choses différentes

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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