IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++Builder Discussion :

comparaison de double [Langage/Algorithme]


Sujet :

C++Builder

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Par défaut comparaison de double
    Bonjour,
    si quelqu'un peut m'expliquer pourquoi ce code se comporte de façon "inattendue", c'est à dire que je passe dans le "if", alors que les 2 valeurs sont identiques.
    Si j'enlève la ligne min*=6 et que j'affecte 1.6 à value1, je ne passe pas dans le if -> comportement attendu.
    C'est le fait de multiplier qui engendre ce comportement.
    Si je remplace les double par des float, le comportement est "correct".
    Un truc sur les "double" qu'il faudrait savoir?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
            double min = 1.6;
    	min *= 6;
     
    	UnicodeString value1 = "9.6";
    	double value2 = value1.ToDouble();
    	if (value2 < min) {
    		....
    	}
    Je vous remercie d'éclairer ma lanterne !
    Pascale38

  2. #2
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    735
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 735
    Par défaut
    Bonjour.

    C'est une question classique en C et C++, traitée dans la FAQ C (mais ça marche aussi pour le C++).

    Mais pour faire simple, une nombre flottant (float et double) ont une précision limitée, des arrondis peuvent avoir lieu et fausser les résultats.

    Typiquement, chez moi, 1.6 est stocké sous la forme 1.60000000000000008 (probablement la valeur la plus proche que la machine puisse stocker). L'imprécision est propagée avec la multiplication et fausse la comparaison.

  3. #3
    Membre Expert
    Avatar de Crayon
    Inscrit en
    Avril 2005
    Messages
    1 811
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 811
    Par défaut
    Avec C++Builder tu peux utiliser Math::CompareValue pour faire des comparaisons de double.

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
        double min = 1.6;
        min *= 6;
     
        UnicodeString value1 = "9.6";
        double value2 = value1.ToDouble();
        const System::Types::TValueRelationship LRelation = Math::CompareValue(value2, min);
        if (LRelation == LessThanValue) {
            // <
        }
        else if (LRelation == GreaterThanValue) {
            // >
        }
        else if (LRelation == EqualsValue) {
            // ==
        }

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    229
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 229
    Par défaut
    Merci !!!!

  5. #5
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    Mais attention à l'utilisation d'outils qui semblent absorber le problème. Le fait que les flottants sont toujours des approximations et ne sont pas des vérités mathématiques ne doit jamais être oublié. Les pièges sont :
    - savoir que le nombre est une approximation. P.e 1.6 est un nombre qui tombe juste en décimal mais qui a une infinité de décimales en binaire (et ici il semble que le 1.6f float est plus petit que le vrai 1.6 et que le 1.6 double est plus grand que le vrai 1.6)
    - savoir qu'effectuer des calculs provoque une amplification de ces approximations y compris sur des nombres entiers. P.e pow(7.0,3.0) peut être différent de 7*7*7 alors que 7.0 et 3.0 sont pourtant toujours exacts.
    - ne jamais effectuer de test d'égalité entre 2 flottants pour les raisons ci-dessus
    - et les tests d'inégalité doivent utiliser une marge de sécurité. en gros on a 4 cas:
    • nombre nettement inférieur
    • nombres presque égaux
    • nombre nettement supérieur
    • nombres non comparables. Très rare (p.e. 0.0/0.0 est ni inférieur, ni supérieur, ni égal à quelque nombre que ce soit, il n'est pas même égal à lui même. C'est normal ça n'est pas un nombre!)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    void tester( double test ) {
        if ( test < 9.6*0.9999 )
            std::cout << test << " est inférieur à 9.6\n";
        else if ( test < 9.6*1.0001 )
            std::cout << test << " est égal ou presque à 9.6, l'écart est " << test-9.6 << "\n";
        else if ( test >= 9.6*1.0001 )
            std::cout <<  test << " est supérieur à 9.6\n";
        else         // oui c'est possible d'arriver là avec des inégalités sur des flottants!
            std::cout << "le 'nombre' " << test << " n'est pas comparable\n";
    }
    int main() {
        double test=1.6;
        test *= 6;
        tester( test );
        test = 0.0;
        test /= 0.0;
        tester( test );
    }

  6. #6
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 763
    Par défaut
    Citation Envoyé par dalfab Voir le message
    pow(7.0,3.0) peut être différent de 7*7*7 alors que 7.0 et 3.0 sont pourtant toujours exacts.
    Pour être précis (mais à confirmer) pour des raisons de nombres négatifs, la fonction pow ne fait pas de multiplication.

    pow(x,y) = exp(y * ln(x))

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Ergotage sur la comparaison de doubles
    Par gangsoleil dans le forum C
    Réponses: 16
    Dernier message: 26/01/2015, 17h11
  2. Comparaison de doubles
    Par Invité dans le forum C
    Réponses: 5
    Dernier message: 19/03/2013, 11h31
  3. switch sur comparaison de double
    Par lovedesitaliens dans le forum C#
    Réponses: 1
    Dernier message: 14/10/2010, 16h25
  4. comparaison de doubles, valeur absolue et perf
    Par ppaul128 dans le forum C++
    Réponses: 10
    Dernier message: 19/05/2008, 14h14
  5. Comparaison de double
    Par bolhrak dans le forum C++
    Réponses: 9
    Dernier message: 17/02/2008, 19h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo