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 :

Bug C++ Builder 6 ? - "while" et doubles


Sujet :

C++Builder

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 7
    Points : 3
    Points
    3
    Par défaut Bug C++ Builder 6 ? - "while" et doubles
    Bonjour, soit c'est un bug dans C++ Builder soit dans ma tête

    Alors, il s'agit de la boucle tant-que de base avec les doubles, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      double i = 0.6;
     
      while (i < 0.8)
      {
        i += 0.1;
      }
    La variable i devrait avoir la valeur 0.8 à la sortie de la boucle tantque, or ce n'est pas le cas ! A la troisième vérification quand i = 0.8, la condition 0.8 < 0.8 n'arrête pas la boucle mais fait passer encore une fois et la valeur de i à la sortie est 0.9 !!!

    J'ai fait des tests et les conditions en dessous de 0.8 fonctionnent : testez par exemple avec while (i < 0.7) et vous verrez...

    Alors, que se passe-t-il ?

    Merci pour vos reponses.

  2. #2
    Rédacteur
    Avatar de blondelle
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    2 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 738
    Points : 3 766
    Points
    3 766
    Par défaut
    majke a ecrit:
    Bonjour, soit c'est un bug dans C++ Builder soit dans ma tête

    Alors, il s'agit de la boucle tant-que de base avec les doubles, par exemple :

    Code :

    double i = 0.6;

    while (i < 0.8)
    {
    i += 0.1;
    }
    La variable i devrait avoir la valeur 0.8 à la sortie de la boucle tantque, or ce n'est pas le cas ! A la troisième vérification quand i = 0.8, la condition 0.8 < 0.8 n'arrête pas la boucle mais fait passer encore une fois et la valeur de i à la sortie est 0.9 !!!

    J'ai fait des tests et les conditions en dessous de 0.8 fonctionnent : testez par exemple avec while (i < 0.7) et vous verrez...

    Alors, que se passe-t-il ?

    Merci pour vos reponses.
    Je pense qu'il faut ecrire ta fonction comme ceci.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      double i = 0.6;
     
      while (i <= 0.8) // <--- Modif
      {
        i += 0.1;
      }

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Août 2002
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 481
    Points : 242
    Points
    242
    Par défaut
    Je pense que 0.6 + 0.1 + 0.1 ne fait pas 0.8.
    Il ne faut pas oublier que les double n'ont pas une infinité de décimales.
    Alors 0.6 + 0.1 +0.1 cela fait peut-être 0.79999999. Et il y a une boucle de plus.

    Pour faire des comparaisons avec des nombre double il faudrait mettre une condition supplémentaire. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    double i = 0.6;
    double

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Août 2002
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 481
    Points : 242
    Points
    242
    Par défaut
    e pense que 0.6 + 0.1 + 0.1 ne fait pas 0.8.J
    Il ne faut pas oublier que les double n'ont pas une infinité de décimales.
    Alors 0.6 + 0.1 +0.1 cela fait peut-être 0.79999999. Et il y a une boucle de plus.

    Pour faire des comparaisons avec des nombre double il faudrait mettre une condition supplémentaire. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    double i = 0.6;
    double err = 0.00001;
    while (i <(0.8 - err))
      {
        i += 0.1;
      }

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par Pasqualini
    Je pense que 0.6 + 0.1 + 0.1 ne fait pas 0.8.
    Il ne faut pas oublier que les double n'ont pas une infinité de décimales.
    Alors 0.6 + 0.1 +0.1 cela fait peut-être 0.79999999. Et il y a une boucle de plus.
    Je suis d'accord avec toi, mais il s'agit de l'informatique, et 0.999999999 peut devenir 1.0 que si on le veut, et il existe des fonctions pour le faire, sans ça 0.999999999 reste 0.999999999 et dons différent de 1.000000000 ...

    L'outil tel que C++ Builder 6 devrait me le montrer, non ?

    Donc, un bug ?

  6. #6
    Rédacteur
    Avatar de blondelle
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    2 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 738
    Points : 3 766
    Points
    3 766
    Par défaut
    Salut majke.
    A tu essaye la modif que je t'ai donnee?

  7. #7
    Membre actif
    Profil pro
    Inscrit en
    Août 2002
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 481
    Points : 242
    Points
    242
    Par défaut
    "Je suis d'accord avec toi, mais il s'agit de l'informatique, et 0.999999999 peut devenir 1.0 que si on le veut, et il existe des fonctions pour le faire, sans ça 0.999999999 reste 0.999999999 et dons différent de 1.000000000 ...

    L'outil tel que C++ Builder 6 devrait me le montrer, non ?

    Donc, un bug ?"

    Il ne s'agit pas d'un bug. Il n'y a aucune raison, si on travaille avec des double qu'un compilateur quelconque transforme un 0.999999 en 1.000000, pourquoi pas en 0;999998 ?

    Il est dangereux de mettre des conditions d'égalité sur des nombres qui ne sont pas des int

  8. #8
    Membre éclairé
    Avatar de Interruption13h
    Inscrit en
    Août 2005
    Messages
    603
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 603
    Points : 786
    Points
    786
    Par défaut
    Salut !

    Ton problème l'a expliqué blondelle

    A+

  9. #9
    Rédacteur
    Avatar de blondelle
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    2 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 738
    Points : 3 766
    Points
    3 766
    Par défaut
    Merci Interruption13h.
    La fonction tel qu'el est ecrite dit si i est strictement superieur a 0.8 (while (i < 0.8))
    Pour qu'elle fonctionne selon le souhait de majke il faut ecrire si i est superieur ou equal a 0.8 (while (i <= 0.8))

    Salut Pasqualini.
    Le fait d'avoir utilise des doubles ne signifie pas que les valeur doivent avoir obligatoirement de nombreuses decimales, majke a initialise sa variable a i = 0.6 et non pas a i = 5.9999 ou i = 6.00111 ses valeurs non rien a voir avec ton explication le choix qu'il a fait d'utiliser des doubles est compatible avec ce qu'il a programme a son erreur de teste pret.

  10. #10
    Membre actif
    Profil pro
    Inscrit en
    Août 2002
    Messages
    481
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 481
    Points : 242
    Points
    242
    Par défaut
    Le nombre 0.6 n'a pas, en binaire, un nombre fini de décimales. C'est donc obligatoirement un approximation de 0.6 qui est créée.

  11. #11
    Membre régulier

    Inscrit en
    Janvier 2003
    Messages
    38
    Détails du profil
    Informations forums :
    Inscription : Janvier 2003
    Messages : 38
    Points : 76
    Points
    76
    Par défaut
    Citation Envoyé par blondelle
    Pour qu'elle fonctionne selon le souhait de majke il faut ecrire si i est superieur ou equal a 0.8 (while (i <= 0.8))
    Non
    Relis bien le premier post.

    La condition est i<0.8 et on passe bien dans la boucle.
    Et ce qu'on veut c'est ne pas passer dans cette boucle.

    Sylvain

  12. #12
    Membre averti

    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    288
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Janvier 2003
    Messages : 288
    Points : 334
    Points
    334
    Par défaut
    Je ne sais pas si cela à un rapport mais à chaque fois que je manipule des constantes décimales, j'utilise la notation suivante:

    f = 0.6f;

    (j'utilise de préférence les floats aux double donc j'illustre mon exemple avec ce que je connais, je ne suis pas sur de la notation en double mais il me semble qu'elle est identique).
    Je crois aussi avoir eux des mauvaises surprises comme celle de majke qui ont été résolues par cette méthose.

    Je vous livre ces réflexions telles quelles, basées seulement sur mon expérience et des souvenirs. En tout cas le "f" ne peux pas faire de mal.

    Yarp
    www.senosoft.com

  13. #13
    Membre chevronné
    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
    Points : 2 189
    Points
    2 189
    Par défaut
    Je sais que ma réflexion ne va pas vraiment aidé à comprendre le problème, mais pourquoi tu ne multiplie pas par 10 et tu traites tout les valeurs comme des entiers

  14. #14
    mat.M
    Invité(e)
    Par défaut
    J'ai essayé avec VC++6.0 et i dans la boucle vaut 0.60000000000000.
    Ce n'est pas un bug de BCB alors je te rassure
    Donc effectivement c'est un problème de précision; il faudrait arrondir ou bien utiliser la technique des entiers de Crayon

  15. #15
    Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par Crayon
    Je sais que ma réflexion ne va pas vraiment aidé à comprendre le problème, mais pourquoi tu ne multiplie pas par 10 et tu traites tout les valeurs comme des entiers
    Hé hé hé, c'est pas faux, mais l'exemple que j'ai donné est là pour essayer de comprendre le problème de base, j'espère donc trouver la réponse à ma question : bug dans Builder ou pas ?
    Jusque là j'ai compris que while n'a rien à voir là dedans (Malheuresment j'ai nommé la discussion Bug C++ Builder 6 ? - "while" et doubles)

    Donc, pour avancer je vais reformuler ma question ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
      double a = 0.7;
      double b = 0.1;
      double c = a + b;
     
      double d = 0.8;
     
      if (c == d) ShowMessage("OK");
    Et puis voilà, le problème est le même : l'addition 0.7 + 0.1 donne 0.8 (le compilateur le montre aussi) mais après ce même c=0.8 est différent de d=0.8 !!! Le message n'est pas affiché !

    Et si l'on fait comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
      double a = 0.6;
      double b = 0.1;
      double c = a + b;
     
      double d = 0.7;
     
      if (c == d) ShowMessage("OK");
    Le message est affiché. Pas de problème.

    0.6 + 0.1 donne 0.7 et
    0.7 + 0.1 donne quoi ?

    J'attends que quelqu'un teste chez lui l'exemple donné sur C++ Builder 5 ou 6, et pourquoi pas Visual C++

    p.s. Merci pour le réflexions de Yarp, je vais l'essayer, mais avant tout il faut que je sois sûr que le compilateur ne me montre pas de bêtises. Il faut comprendre la différence entre un float et un double.
    p.p.s. Pasqualini t'as raison en partie, mais si c'est comme ça je veux que la machine (le compilateur) me le montre, je peux pas savoir ce qui se passe derrière.
    p.p.p.s Peux tu essayer mat.M avec ces exemples d'addition aussi stp.

  16. #16
    Membre chevronné
    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
    Points : 2 189
    Points
    2 189
    Par défaut
    J'ai trouvé post sur un goupe de discussion qui parle de comment comparer deux double : http://groups.google.com/group/micro...94acad1?hl=en&

    En voici un extrait:

    C++ way is

    if (x == y) {...}

    Smart engineer's way is

    if (fabs(x - y) < eps) {...}

    where eps is a small number, carefully chosen by aforementioned smart
    engineer based on his/her accuracy requirements and error accumulation
    estimates.
    Je pense qu'il n'y a pas de moyen parfait, il faut arrondire et avoir un certain range d'erreur.

  17. #17
    mat.M
    Invité(e)
    Par défaut
    Citation Envoyé par majke
    p.p.p.s Peux tu essayer mat.M avec ces exemples d'addition aussi stp.
    ça va couter cher

    c et d valent 0.80000000000000 mais l'égalité ne se vérifie pas ..


    Si on déclare double d = 0.8f;
    d vaut 0.80000001192093 en déboguage pas-à-pas

  18. #18
    Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par mat.M
    ça va coûter cher
    Tu acceptes les €uros ?
    Citation Envoyé par mat.M
    c et d valent 0.80000000000000 mais l'égalité ne se vérifie pas ..
    Oui, voilà donc il s'avère que le compilateur de VC++6.0 et de BCB 6.0 fonctionnent de même manière. Sauf que pour un double déclaré comme ça :, le débogage pas-à-pas de VC++ montre 0.80000000000000 et celui de BCB montre 0.8.
    Puis l'égalité ne se vérifie pas, effectivement il y'a une approximation (qui est comprehensible car le stockage et manipulation de valeur décimales dans la mémoire n'est pas simple) mais ceci nous n'est pas montrée lors de débogage !
    Par contre pour les float la situation est aussi compliquée mais nettement plus claire lors de débogage comme le montre mat.M dans VC++ :

    Citation Envoyé par mat.M
    Si on déclare double d = 0.8f;
    d vaut 0.80000001192093 en débogage pas-à-pas
    Pour être plus clair, si dans BCB 6.0 je déclare un float comme ceci : , le déboggeur de BCB 6.0 me montre que a vaut 0.80000001192 et si j'affiche cette valeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ShowMessage( FloatToStr(a) );
    je peux voir la valeur effective : 0.800000011920929 car la précision de float en BCB 6.0 est sur 15 chiffres (écrit dans l'aide).
    Les questions que je me pose :
    - pourquoi il y a une différence entre un float et un double ? (ShowMessage d'un double montre toujours ce qu'on a déclaré càd 0.8 et dans le cas d'addition 0.7+0.1 c'est aussi 0.8 même si l'égalité de deux 0.8 ne se vérifie pas...)
    - pourquoi lors de débogage un float 0.8 est montré sur 11 décimales alors que ça valeur réele après l'approximation est sur 15 décimales. Je dois faire un ShowMessage ou Ansistring s = FloatToStr(a); pour voir ça valeur réele. Là on peut parler d'un bug d'affichage dans le débogage pas à pas de BCB 6.0 ...

  19. #19
    Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    J'ai fait le test suivant avec les float et l'égalité se vérifie bien , pas comme avec les double :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    float a = 0.7;
    float b = 0.1;
    float c = a + b;
     
    float d = 0.8;
     
    if (c == d) ShowMessage("OK");
    Voici les valeurs montrées lors de débogage (sur 11 chiffres) puis les valeurs réelles (sur 15 chiffres) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    a 0,69999998808
    b 0,10000000149
    c 0,80000001192
    d 0,80000001192
     
    a 0,699999988079071
    b 0,100000001490116
    c 0,800000011920929
    d 0,800000011920929
    On peut voir que lors de l'affichage la valeur de a est arrondie à 11 décimales, il n'y a pas que 4 dernières chiffres qui sont enlevées !
    Et puis en maths 0,699999988079071 + 0,100000001490116 = 0,799999989569187 mais c'est une autre histoire, il faut revoir ses cours d'architecture d'ordinateurs pour voir comment l'addition fonctionne (je les avais pas pris au sérieux à l'époque )

    Donc comparer deux float est plus facile que deux double, il faut voir le lien que Crayon a passé.
    Et concernant l'affichage de compilateur je vais lancer un sujet sur le forum de Borland. Peut être qu'il y a de mises à jour à faire...

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