Rechercher : dans
Par :

[C ANSI] Comparer des DOUBLES ?comment

Dernière réponse le 22 nov 2005 à 10:13:22 sylvie, le 20 nov 2005 à 17:37:11 
 Signaler ce message aux modérateurs

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/

Configuration: OS: WIN XP SP2 & BUNTU BREEZY
EDI: Dev cpp & Ajanta sous LINUX.
Compilation: gcc -wall -ansi

Meilleures réponses pour « [C ANSI] Comparer des DOUBLES ?comment » dans :
Liste doublement chaînée VoirLISTES DOUBLEMENT CHAINÉES Requis I. INTRODUCTION II. Définition III. La construction du prototype d'un élément de la liste IV. Opérations sur les listes doublement chaînées A. Initialisation B. Insertion d'un élément dans la liste 1....
Langage C++ - Les types de données VoirLes types de données Les données manipulées en langage C++, comme en langage C, sont typées, c'est-à-dire que pour chaque donnée que l'on utilise (dans les variables par exemple) il faut préciser le type de donnée, ce qui permet de connaître...
Langage C - Les types de données VoirLes types de données Les données manipulées en langage C sont typées, c'est-à-dire que pour chaque donnée que l'on utilise (dans les variables par exemple) il faut préciser le type de donnée, ce qui permet de connaître l'occupation mémoire (le...
Langage C++ - Les opérateurs VoirQu'est-ce qu'un opérateur ? Les opérateurs sont des symboles qui permettent de manipuler des variables, c'est-à-dire effectuer des opérations, les évaluer, etc. On distingue plusieurs types d'opérateurs : les opérateurs de calcul les opérateurs...

1

Char Snipeur, le 20 nov 2005 à 23:46: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. Salutation !
Char Snipeur

Répondre à Char Snipeur

2

mamiemando, le 21 nov 2005 à 10:35:27

Ca existe pas les long double ?

Répondre à mamiemando

3

Marden, le 21 nov 2005 à 12:44:14

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).

Répondre à Marden

4

sylvie, le 21 nov 2005 à 13:17:41

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.

Répondre à sylvie

5

sylvie, le 21 nov 2005 à 13:19:06

Sinon que pensez vous de la méthode qui constitue pour comparer des flottants a les transformer en chaine et faire un STRCMP?

Répondre à sylvie

6

Marden, le 21 nov 2005 à 14:13:18

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.

Répondre à Marden

7

mamiemando, le 21 nov 2005 à 15:18:31

On peut voir le code actuel si ce n'est pas indiscret ?
As-tu essayé les long double ?

Répondre à mamiemando

8

Char Snipeur, le 21 nov 2005 à 17:12:57

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. Salutation !
Char Snipeur

Répondre à Char Snipeur

9

mamiemando, le 21 nov 2005 à 20:00:21

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 ?

Répondre à mamiemando

10

sylvie, le 21 nov 2005 à 20:32:05

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

Répondre à sylvie

11

sylvie, le 21 nov 2005 à 20:34:06

Oublie HS
a CHQR SNIPEUR UNIquement
Ajunta et pas ajanta
http://anjuta.sourceforge.net/

Répondre à sylvie

12

Char Snipeur, le 22 nov 2005 à 09:53:18

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. Salutation !
Char Snipeur

Répondre à Char Snipeur

13

 mamiemando, le 22 nov 2005 à 10:13:22

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 !).

Répondre à mamiemando