[C ANSI] Comparer des DOUBLES ?comment [Fermé]

Signaler
-
mamiemando
Messages postés
29238
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
27 mars 2020
-
Bonjour
je réalise une petit programme en C ANSI avec des chiffres avec 30 chiffres après la virgule maximum.

J'aimerais faire des comparaisons entre mes chiffres apres les calculs mais le problème est que jai une perte de précision engendrant des comparaison d'égalité FAUSSE/

Comment résoudre cela?
On m'a parlé d'epsilon.. mais cela ne fonctionne pas ou lutot je ne sais comment lutiliser.

Merci d'avance/

13 réponses

Messages postés
1072
Date d'inscription
dimanche 11 février 2001
Statut
Membre
Dernière intervention
29 janvier 2006
206
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 :
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).
1
Merci

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

CCM 75376 internautes nous ont dit merci ce mois-ci

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".
1
Merci

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

CCM 75376 internautes nous ont dit merci ce mois-ci

Messages postés
9713
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
13 septembre 2019
1 137
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.
Messages postés
29238
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
27 mars 2020
6 809
Ca existe pas les long double ?
Bonjour
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?
Messages postés
1072
Date d'inscription
dimanche 11 février 2001
Statut
Membre
Dernière intervention
29 janvier 2006
206
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.
Messages postés
29238
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
27 mars 2020
6 809
On peut voir le code actuel si ce n'est pas indiscret ?
As-tu essayé les long double ?
Messages postés
9713
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
13 septembre 2019
1 137
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.
Messages postés
29238
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
27 mars 2020
6 809
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 ?
oublie HS
a CHQR SNIPEUR UNIquement
Ajunta et pas ajanta
http://anjuta.sourceforge.net/
Messages postés
9713
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
13 septembre 2019
1 137
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.
Messages postés
29238
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
27 mars 2020
6 809
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 :
        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 !).