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 Discussion :

Boucle for, problème aux bords


Sujet :

C

  1. #1
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2006
    Messages
    53
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2006
    Messages : 53
    Points : 26
    Points
    26
    Par défaut Boucle for, problème aux bords
    J'ai un problème :

    Je n'arrive pas faire aller les boucle for jusqu'au bout.
    Par exemple, avec le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    float a=4;
    float b=7;
     
    float f;
    for(f=a;f<=b;f+=0.1) {
    	printf("%f\n", f);
    }
    f ne va que jusqu'à 6.9.
    Les valeurs successives de f ne sont pas 4, 4.1, 4.2, ...
    mais 4, 4,10008, 4,20003, ...
    Comment remédier à ce problème ?
    Merci

  2. #2
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par dword2add
    J'ai un problème :

    Je n'arrive pas faire aller les boucle for jusqu'au bout.
    Par exemple, avec le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    float a=4;
    float b=7;
     
    float f;
    for(f=a;f<=b;f+=0.1) {
    	printf("%f\n", f);
    }
    f ne va que jusqu'à 6.9.
    Les valeurs successives de f ne sont pas 4, 4.1, 4.2, ...
    mais 4, 4,10008, 4,20003, ...
    Comment remédier à ce problème ?
    Merci
    C'est un problème inhérent à l'utilisation des flottants (la valeur est le plus souvent une approximation).

    Je recommande l'usage des double
    - Meilleure précision
    - Code natif fait pour les doubles (pas de conversion)
    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
     
    #include <stdio.h>
    #include <float.h>
     
    int main (void)
    {
       double a = 4;
       double b = 7;
       double f;
     
       for (f = a; f <= b; f += 0.1)
       {
          printf ("%f\n", f);
       }
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    4.000000
    4.100000
    4.200000
    4.300000
    ...
    6.800000
    6.900000
    7.000000
     
    Press ENTER to continue.

  3. #3
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2006
    Messages
    53
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2006
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    Sur mon compilateur quand j'affiche des doubles il n'y a pas plus de décimal, c'est normal ?

  4. #4
    Membre régulier Avatar de elghadi_mohamed
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2005
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Service public

    Informations forums :
    Inscription : Décembre 2005
    Messages : 227
    Points : 89
    Points
    89
    Par défaut
    Citation Envoyé par dword2add
    Sur mon compilateur quand j'affiche des doubles il n'y a pas plus de décimal, c'est normal ?
    c'est quoi ton environnement de programmat...?

    decimale ???

  5. #5
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par dword2add
    Sur mon compilateur quand j'affiche des doubles il n'y a pas plus de décimal, c'est normal ?
    Si tu utilises "%d", c'est normal. C'est "%f"...

  6. #6
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2006
    Messages
    53
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2006
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    J'utilise Mingw-32-g++
    J'utilise la commande c++ cout.

  7. #7
    Membre expérimenté
    Avatar de Gruik
    Profil pro
    Développeur Web
    Inscrit en
    Juillet 2003
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juillet 2003
    Messages : 1 566
    Points : 1 729
    Points
    1 729
    Par défaut
    Et oui, tu peux pas tester l'égalité entre 2 flottants, tu peux juste mesurer la difference (=> tester lequel est le plus grand)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    float a=4;
    float b=7;
    float f;
    for(f=a;f<=b + 0.001f;f+=0.1)
    { 
      printf("%f\n", f);
    }
    Sinon, oui, on ne devrait utiliser que des doubles, à part si on a besoin d'économiser de la memoire

  8. #8
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par dword2add
    J'utilise Mingw-32-g++
    J'utilise la commande c++ cout.
    Et c'est sans doute la raison pour laquelle tu postes dans le forum C ! C'était de la bonne ?

    Le forum C++, c'est à coté.

  9. #9
    Membre expérimenté
    Avatar de Gruik
    Profil pro
    Développeur Web
    Inscrit en
    Juillet 2003
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juillet 2003
    Messages : 1 566
    Points : 1 729
    Points
    1 729
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    C'était de la bonne ?
    ptdr

  10. #10
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Des nombres comme 0.1 et 4.2 ne sont pas représentable exactement dans les formats courants de flottant. Donc ils sont remplacés par des nombres légèrement plus grand ou plus petit, apparemment en float 0.1 donne un nombre légèrement plus grand, donc tu dépasses la borne, en double un nombre légèrement plus petit et pour Emmanuel ça passe par chance. Ma solution serait de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int i;
    for (i = 30; i <= 70; i += 1) {
       float f = i/10.0;
    }
    qui n'évite pas une erreur sur f, mais au moins évite qu'elle soit le résultat de l'accumulation de l'erreur faite sur 0.1. Si les bornes te sont données au départ dans des flottants, le problème est beaucoup plus complexe car sauf cas particuliers, une erreur est déjà présente. Suivant ce qu'on sait des nombres au départ, il est possible qu'on puisse s'en sortir.

  11. #11
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par dword2add
    Sur mon compilateur quand j'affiche des doubles il n'y a pas plus de décimal, c'est normal ?
    Parce qu'en C comme en C++, le format utilisé par les sorties formatées est déterminé de la même façon pour les floats et pour les doubles.

  12. #12
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int i;
    for (i = 30; i <= 70; i += 1) {
       float f = i/10.0;
    }
    qui n'évite pas une erreur sur f, mais au moins évite qu'elle soit le résultat de l'accumulation de l'erreur faite sur 0.1.
    +1.

    J'avais oublié cette astuce. Il faut absolument éviter les itérateurs de type flottants quand c'est possible, quitte à recalculer la valeur à chaque fois en fonction des limites et du pas.

  13. #13
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    Parce qu'en C comme en C++, le format utilisé par les sorties formatées est déterminé de la même façon pour les floats et pour les doubles.
    Ah, OK. Par 'plus de décimales', il entend 'tout à 0' et non 'rien' (comme un entier).

  14. #14
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Ah, OK. Par 'plus de décimales', il entend 'tout à 0' et non 'rien' (comme un entier).
    J'ai compris qu'il avait toujours un affichage avec 6 chiffres significatifs que ce soit pour des floats ou des doubles, ce qui est normal (surtout en C ou les promotions sur les arguments des fonctions variadiques font qu'on ne passe pas des float à printf).

  15. #15
    Nouveau membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Septembre 2006
    Messages
    53
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2006
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    OK, merci pour vos réponses.

  16. #16
    Membre émérite

    Homme Profil pro
    Inscrit en
    Juillet 2003
    Messages
    2 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ardennes (Champagne Ardenne)

    Informations forums :
    Inscription : Juillet 2003
    Messages : 2 075
    Points : 2 844
    Points
    2 844
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    Des nombres comme 0.1 et 4.2 ne sont pas représentable exactement dans les formats courants de flottant. Donc ils sont remplacés par des nombres légèrement plus grand ou plus petit, apparemment en float 0.1 donne un nombre légèrement plus grand, donc tu dépasses la borne, en double un nombre légèrement plus petit et pour Emmanuel ça passe par chance. Ma solution serait de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int i;
    for (i = 30; i <= 70; i += 1) {
       float f = i/10.0;
    }
    qui n'évite pas une erreur sur f, mais au moins évite qu'elle soit le résultat de l'accumulation de l'erreur faite sur 0.1. Si les bornes te sont données au départ dans des flottants, le problème est beaucoup plus complexe car sauf cas particuliers, une erreur est déjà présente. Suivant ce qu'on sait des nombres au départ, il est possible qu'on puisse s'en sortir.
    On peut aussi utiliser un opérateur de formatage non? Qque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
    #include <stdlib.h>
     
    int main (void)
    {
      float a = 4.0;
      float b = 7.0;
      float f;
     
      for (f=a; f < b; f += 0.1){ 
        printf ( "%.01f\n", f);
      }
      return EXIT_SUCCESS;
    }
    me donne le résultat que l'OP a l'air d'attendre non?

  17. #17
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Gnux
    On peut aussi utiliser un opérateur de formatage non?
    Le formatage peut masquer le problème. Mais il était surtout révélé par le fait que l'OP voulait que la boucle soit exécutée pour les bornes... ce que ton exemple ne fait pas.

    À propos de boucle exécutée pour les bornes, le C est pénible même pour les entiers. Comment faite vous pour une boucle de a à b, exécutée pour les bornes en sachant que celles-ci peuvent être LONG_MIN ou LONG_MAX ou même indiquer un intervalle nul. Ma meilleure solution est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if (a < b) {
       long i = a;
       do {
          /* corps de la boucle */
       } while (i != b ? ++i, 1 : 0);
    }
    qui n'est guère satisfaisante.

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

Discussions similaires

  1. Boucle for problème argument
    Par mickeys dans le forum Général Python
    Réponses: 8
    Dernier message: 30/01/2015, 15h49
  2. [XL-2003] VBA boucle for - problème incrémentation
    Par HankMoody dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 20/07/2012, 17h31
  3. Réponses: 31
    Dernier message: 02/04/2012, 18h29
  4. Réponses: 2
    Dernier message: 18/09/2008, 12h22
  5. boucle for, problème !
    Par haricot75 dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 08/02/2007, 17h51

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