[C ANSI] Comparer des DOUBLES ?comment

Fermé
sylvie - 20 nov. 2005 à 17:37
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 - 22 nov. 2005 à 10:13
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/
A voir également:

13 réponses

Marden Messages postés 1072 Date d'inscription dimanche 11 février 2001 Statut Membre Dernière intervention 29 janvier 2006 208
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 :
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
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
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
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.
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
21 nov. 2005 à 10:35
Ca existe pas les long double ?
0

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.

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.
0
sinon que pensez vous de la méthode qui constitue pour comparer des flottants a les transformer en chaine et faire un STRCMP?
0
Marden Messages postés 1072 Date d'inscription dimanche 11 février 2001 Statut Membre Dernière intervention 29 janvier 2006 208
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.
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
21 nov. 2005 à 15:18
On peut voir le code actuel si ce n'est pas indiscret ?
As-tu essayé les long double ?
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
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.
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
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 ?
0
oublie HS
a CHQR SNIPEUR UNIquement
Ajunta et pas ajanta
http://anjuta.sourceforge.net/
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
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.
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
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 :
        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 !).
0