[C ANSI] Comparer des DOUBLES ?comment
Fermé
sylvie
-
20 nov. 2005 à 17:37
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 22 nov. 2005 à 10:13
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 22 nov. 2005 à 10:13
A voir également:
- [C ANSI] Comparer des DOUBLES ?comment
- Comparer prix amazon - Accueil - Commerce
- Comment faire un double ecran - Guide
- Comment prendre un double appel sur samsung - Guide
- Comment supprimer des photos en double sur pc - Guide
- Comparer deux photos pour savoir si c'est la meme personne - Forum Graphisme
13 réponses
Marden
Messages postés
1072
Date d'inscription
dimanche 11 février 2001
Statut
Membre
Dernière intervention
29 janvier 2006
210
21 nov. 2005 à 12:44
21 nov. 2005 à 12:44
Rappelons d'abord que le C ne manipule pas des "chiffres" mais des "nombres" (entiers ou réels) comme indiqués sur cette page :
http://www.commentcamarche.net/c/ctype.php3
Le nombre de "chiffres" (caractères de "0" à 9") s'applique à la représentation décimale, alors que le langage traite de valeurs utilisant le binaire. La représentation des nombres réels (ou flottants) en machine est de la forme :
{signe} * {mantisse} * { 2 ^ exposant}.
Le nombre de bits pour l'exposant et pour la mantisse dépend du type choisi (float/32bits, double/64bits ou long double/80bits).
Une conversion est appliquée donc en entrée (dont les opérations d'affection ou de lecture) et en sortie (pour l'édition de résultats). Le premier type de conversion ne donne pas nécessairement la représentation exacte de la valeur d'entrée (un peu comme 1 divisé par 3 --> 0.333333.....). Quelque soit le type choisi, les calculs entraîneront une perte de précision notamment dans l'addition d'un très grand nombre avec un très petit (avec des exposants "très" différents) ou dans la soustraction de nombres dont les valeurs sont "très" proches. Les méthodes pour réduire cette perte de précision ne sont pas à la portée du premier venu il y a des gens qui passent leur temps à en chercher de nouvelles.
Désolé pour la longueur de ce préambule !
Dans le cas qui nous concerne, la solution peut être simplement de la forme :
http://www.commentcamarche.net/c/ctype.php3
Le nombre de "chiffres" (caractères de "0" à 9") s'applique à la représentation décimale, alors que le langage traite de valeurs utilisant le binaire. La représentation des nombres réels (ou flottants) en machine est de la forme :
{signe} * {mantisse} * { 2 ^ exposant}.
Le nombre de bits pour l'exposant et pour la mantisse dépend du type choisi (float/32bits, double/64bits ou long double/80bits).
Une conversion est appliquée donc en entrée (dont les opérations d'affection ou de lecture) et en sortie (pour l'édition de résultats). Le premier type de conversion ne donne pas nécessairement la représentation exacte de la valeur d'entrée (un peu comme 1 divisé par 3 --> 0.333333.....). Quelque soit le type choisi, les calculs entraîneront une perte de précision notamment dans l'addition d'un très grand nombre avec un très petit (avec des exposants "très" différents) ou dans la soustraction de nombres dont les valeurs sont "très" proches. Les méthodes pour réduire cette perte de précision ne sont pas à la portée du premier venu il y a des gens qui passent leur temps à en chercher de nouvelles.
Désolé pour la longueur de ce préambule !
Dans le cas qui nous concerne, la solution peut être simplement de la forme :
if ( a >= b - epsilon && a <= b + epsilon ) ...qui considère que les nombres a et b sont identiques à epsilon près (à définir en fonction des besoins).
J'ai 4 points donnés.Je simplifie volontairement le code sans montrer les structures utilisés et les points sont farfelus.
//point 1
float x1=42.15637281638281; float y1=42.15637281638281;
...
</code
Ces point (parmi d'autres) sont donnés dans un fichier et correspondent au coordonées d'1 point dans un repère orthonormée en x,y.
Mon but:
savoir si le point de coordonée px,py appartient a ce plan cad si entre autres:
je cherche a réaliser lopération suivante pout savoir si un point est en dessous d1 droite d1 en ordonnée.
a2 x p1<=y et a2 x p1=>y
ou a2, p1 et y sont du meme type que x1, x2 (a savoir float avec jusque 15 chiffres en général apres la virgule)
Or lorsque par malheur:
a2 x p1==y est vrai en théorie cela plante malgré que je suis sur quils sont mathématiquement EGAUX (chose vérifié) car ils nont que 15 chiffres apres la virgule exactement sans ARRONDI.
je vais essayer pour le EPSILON vous me conseillez de lui donne quell valeur?car jai toujours du mal a comprendre le conseil donné sur les autres "determiner un EPSILON judicieux".
Char Snipeur
Messages postés
9813
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
3 octobre 2023
1 298
20 nov. 2005 à 23:46
20 nov. 2005 à 23:46
Salut.
je suppose que tu utilise des double pôur tes calculs.
Ta limite est mathématique autant qu' informatique.
tes nombres sont codés sur un certain nombre de bits, le fait que tu n'es pas un nombre infini de bit entraine de fait une certaine erreur lors de calculs.
Pour la diminuer, il faut augmenter le nombre de bits.
à ma connaissance, c'est difficilement fesable en C.
Il me semble que le type qui utiulise le plus de bit est "double double".
sinon, tu peux aussi ruser : si tu connait la valeur du nombre autour du quel tourne ta valeur, il suffit de s'intéresser qu'aux derniers nombres.
ex : 3.1415946468 et 3.1415946764, tu ne compare que 468 et 764.
Voila, peu pas plus t'aider.
bonne chance.
PS: où a tu trouver Ajanta, aucune trace sur le oueb.
je suppose que tu utilise des double pôur tes calculs.
Ta limite est mathématique autant qu' informatique.
tes nombres sont codés sur un certain nombre de bits, le fait que tu n'es pas un nombre infini de bit entraine de fait une certaine erreur lors de calculs.
Pour la diminuer, il faut augmenter le nombre de bits.
à ma connaissance, c'est difficilement fesable en C.
Il me semble que le type qui utiulise le plus de bit est "double double".
sinon, tu peux aussi ruser : si tu connait la valeur du nombre autour du quel tourne ta valeur, il suffit de s'intéresser qu'aux derniers nombres.
ex : 3.1415946468 et 3.1415946764, tu ne compare que 468 et 764.
Voila, peu pas plus t'aider.
bonne chance.
PS: où a tu trouver Ajanta, aucune trace sur le oueb.
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
21 nov. 2005 à 10:35
21 nov. 2005 à 10:35
Ca existe pas les long double ?
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Bonjour
en fait jai des résultts en moyenne en générale 15 chiffres apres la virgule.
Justement TOUT EST LA mon probleme: [b]comment déterminer JUDICIEUSEMENT le FAMEUS EPSILON? [/b]Quelle méthode utilisée? car jai déja essayé est selon lepsilon le truc est FAUX ou JUSTE.
Ajanta est un environnement développé du genre devcpp sous Linux MAIS etrangement je ne le trouve pas sur GOOGLE? viré de leur BD? en tout cas je lui eu sur synaptic depuis ubuntu. mais Ajanat est vraiment pas mal pour un Habtiué a Devcpp.
Si tu le veux vraiment je dois revoir chez moi l'adresse de leur site.
en fait jai des résultts en moyenne en générale 15 chiffres apres la virgule.
Dans le cas qui nous concerne, la solution peut être simplement de la forme : if ( a >= b - epsilon && a <= b + epsilon ) ... qui considère que les nombres a et b sont identiques à epsilon près (à définir en fonction des besoins).
Justement TOUT EST LA mon probleme: [b]comment déterminer JUDICIEUSEMENT le FAMEUS EPSILON? [/b]Quelle méthode utilisée? car jai déja essayé est selon lepsilon le truc est FAUX ou JUSTE.
Ajanta est un environnement développé du genre devcpp sous Linux MAIS etrangement je ne le trouve pas sur GOOGLE? viré de leur BD? en tout cas je lui eu sur synaptic depuis ubuntu. mais Ajanat est vraiment pas mal pour un Habtiué a Devcpp.
Si tu le veux vraiment je dois revoir chez moi l'adresse de leur site.
sinon que pensez vous de la méthode qui constitue pour comparer des flottants a les transformer en chaine et faire un STRCMP?
Marden
Messages postés
1072
Date d'inscription
dimanche 11 février 2001
Statut
Membre
Dernière intervention
29 janvier 2006
210
21 nov. 2005 à 14:13
21 nov. 2005 à 14:13
La méthode consistant à convertir les résultats en chaînes, pour ensuite comparer ces chaînes, est sûrement un très mauvaise méthode : coûteuse en temps de traitement, et pas plus efficace quant au résultat espéré (l'emploi de "epsilon" est simplement remplacé par un nombre de chiffres pour la comparaison).
Ce n'est en tous cas ni un problème de langage, ni un problème d'environnement. Cela dépend plus du domaine d'application : s'il s'agit de déterminer l'âge du capitaine, "epsilon = 0.5" devrait suffire, s'il s'agit de comparer des sommes en euros, il existe des textes législatifs sur lesquels s'appuyer.
Dans la pluparet des cas, le pifomètre et les essais peuvent aussi fonctionner, en fonction du contexte et des résultats attendus. Sinon, il vaut mieux confier le problème à des spécialistes.
Ce n'est en tous cas ni un problème de langage, ni un problème d'environnement. Cela dépend plus du domaine d'application : s'il s'agit de déterminer l'âge du capitaine, "epsilon = 0.5" devrait suffire, s'il s'agit de comparer des sommes en euros, il existe des textes législatifs sur lesquels s'appuyer.
Dans la pluparet des cas, le pifomètre et les essais peuvent aussi fonctionner, en fonction du contexte et des résultats attendus. Sinon, il vaut mieux confier le problème à des spécialistes.
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
21 nov. 2005 à 15:18
21 nov. 2005 à 15:18
On peut voir le code actuel si ce n'est pas indiscret ?
As-tu essayé les long double ?
As-tu essayé les long double ?
Char Snipeur
Messages postés
9813
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
3 octobre 2023
1 298
21 nov. 2005 à 17:12
21 nov. 2005 à 17:12
Ajanta m'interesse, je ne trouve pas d'editeur à la fois simple et complet comme devCpp sous Linux. J'ai essayer VIDE, mais je n'en suis pas totalement satisfait. Donc si tu retombe sur ton lien...
Pour ton problème.
J'ai déjà eu des problèmes similaire. au lieu d'utiliser un epsilon en plus, j'utilise en fois, comme ça tu as une erreur relative :
if (abs(a-b)/(a+b)*2<epsilon)
en prenant espilon de l'ordre de 1e-20 ou ce qu'il te faut.
Mais je trouve ça dommage qu'on ne puisse pas en C faire varier le nombre de bit affecter à la mantisse et à l'exposant.
attention au long double, des fois il est pris comme double, selon compilateur, OS et machine.
Pour ton problème.
J'ai déjà eu des problèmes similaire. au lieu d'utiliser un epsilon en plus, j'utilise en fois, comme ça tu as une erreur relative :
if (abs(a-b)/(a+b)*2<epsilon)
en prenant espilon de l'ordre de 1e-20 ou ce qu'il te faut.
Mais je trouve ça dommage qu'on ne puisse pas en C faire varier le nombre de bit affecter à la mantisse et à l'exposant.
attention au long double, des fois il est pris comme double, selon compilateur, OS et machine.
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
21 nov. 2005 à 20:00
21 nov. 2005 à 20:00
Char sniper : Utilises vi ou kdevelop
Sylvie : est tu sûre que tu as vraiment besoin des 30 décimales. Je veux dire, n'y a t'il pas moen de contourner le problème pour avoir a manipuler des nombres pareils ??? Est ce qu'on peut voir le code que tu fais ?
Sylvie : est tu sûre que tu as vraiment besoin des 30 décimales. Je veux dire, n'y a t'il pas moen de contourner le problème pour avoir a manipuler des nombres pareils ??? Est ce qu'on peut voir le code que tu fais ?
Char Snipeur
Messages postés
9813
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
3 octobre 2023
1 298
22 nov. 2005 à 09:53
22 nov. 2005 à 09:53
Merci pour le lien, je vais essayer ce logiciel.
Pour déterminé ton epsilon judicieusement.
Tu prend tes deux nombre egaux qui ne le sont pas par "==" et tu essai différentes valeurs de epsilon jusqu'a ce que ça fonctionne.
Le problème suivant est : ce epsilon est-il valable pour des valeurs différentes de celles sur lesquelles il a été calculé? C'est pour ça que la méthode que je t'ai proposé avant me parait être la meilleur. En utilisant une ereur relative, tu t'affranchi de la valeur reel de tes nombres.
bonne chance.
Pour déterminé ton epsilon judicieusement.
Tu prend tes deux nombre egaux qui ne le sont pas par "==" et tu essai différentes valeurs de epsilon jusqu'a ce que ça fonctionne.
Le problème suivant est : ce epsilon est-il valable pour des valeurs différentes de celles sur lesquelles il a été calculé? C'est pour ça que la méthode que je t'ai proposé avant me parait être la meilleur. En utilisant une ereur relative, tu t'affranchi de la valeur reel de tes nombres.
bonne chance.
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
22 nov. 2005 à 10:13
22 nov. 2005 à 10:13
Déjà utilise des doubles, plus précis que les floats.
http://www.usenet-fr.net/fur/comp/lang/faq-c-3.html
11.4 Mes calculs flottants me donnent des résultats étranges et/ou différents selon les plateformes
Pour commencer, relisez 11.1. (NDLR : le 11.1 dit : utilise des doubles ^^)
Si le problème est plus complexe, il convient de se rappeler que
les ordinateurs utilisent des formats de représentation des
flottants qui ne permettent pas des calculs exacts. Pertes de
précision, accumulation d'erreurs et autres anomalies sont le lot
commun du numéricien.
Rappelez-vous qu'aucun calcul sur des flottants n'a de chance
d'être exact, en particulier, n'utilisez jamais == entre
deux flottants.
Ces problèmes ne sont pas spécifiques au C.
Dans certains problèmes, une solution peut être d'introduire un
petit paramètre de relaxation, par exemple #define EPS
1e-10, puis de multiplier l'un des termes (judicieusement
choisi) de vos calculs par (1 + EPS).
Pour plus de renseignements, on se reportera par exemple aux
Numerical Recipes ou à Numerical Algorithms
with C (cf. 3.9).
11.5 Comment simuler == entre des flottants ?
Étant donné qu'il y a perte de précision très vite, pour comparer
deux valeurs flottantes, on teste si elles sont assez
proches. Plutôt que d'écrire une horreur du genre :
on écrira :
où l'on aura judicieusement choisi epsilon
(non-nul !).
http://www.usenet-fr.net/fur/comp/lang/faq-c-3.html
11.4 Mes calculs flottants me donnent des résultats étranges et/ou différents selon les plateformes
Pour commencer, relisez 11.1. (NDLR : le 11.1 dit : utilise des doubles ^^)
Si le problème est plus complexe, il convient de se rappeler que
les ordinateurs utilisent des formats de représentation des
flottants qui ne permettent pas des calculs exacts. Pertes de
précision, accumulation d'erreurs et autres anomalies sont le lot
commun du numéricien.
Rappelez-vous qu'aucun calcul sur des flottants n'a de chance
d'être exact, en particulier, n'utilisez jamais == entre
deux flottants.
Ces problèmes ne sont pas spécifiques au C.
Dans certains problèmes, une solution peut être d'introduire un
petit paramètre de relaxation, par exemple #define EPS
1e-10, puis de multiplier l'un des termes (judicieusement
choisi) de vos calculs par (1 + EPS).
Pour plus de renseignements, on se reportera par exemple aux
Numerical Recipes ou à Numerical Algorithms
with C (cf. 3.9).
11.5 Comment simuler == entre des flottants ?
Étant donné qu'il y a perte de précision très vite, pour comparer
deux valeurs flottantes, on teste si elles sont assez
proches. Plutôt que d'écrire une horreur du genre :
double a, b; /* ... */ if (a == b) /* HORREUR ! */ /* ... */
on écrira :
#include <math.h> /* ... */ double a, b; /* ... */ if (fabs (a - b) <= epsilon * fabs (a) ) /* ... */
où l'on aura judicieusement choisi epsilon
(non-nul !).