Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème étrange d'arrondie

    15 octobre 2019 à 19:37:12

    Bonsoir,

    je travaille sur un exercice de TP optionnel qui consiste à créer un programme qui, à l'entrer d'une valeur réel positive, renvoie le nombre de pièce(s) de monnaie minimum pour réaliser la somme entrée. La contrainte est de ne pas utiliser d'instructions conditionnelles.

    J'ai donc programmer cette fonction :

    void minPiece(float somme){ 
      
      int E_2 = (int)(somme/2.f);
      somme = somme - (float)E_2*2.f;
      int E_1 = (int)(somme/1.f);
      somme = somme - (float)E_1*1.f;
      int C_50 = (int)(somme/0.5f);
      somme = somme - (float)C_50*.5f;
      int C_20 = (int)(somme/0.2f);
      somme = somme - (float)C_20 * .2f;
      int C_10 = (int)(somme/0.1f);
      somme = somme - (float)C_10 *.1f;
      int C_5 = (int)(somme/0.05f);
      somme = somme - (float)C_5*.05f;
      int C_2 = (int)(somme/0.02f);
      somme = somme - (float)C_2*.02f;
      int C_1 = (int)(somme/0.01f);
      printf("Pour payer il vous faut :\n %d piece de 2 euros\n %d piece de 1 euro\n %d piece de 50 centimes\n %d piece de 20 centimes\n %d piece de 10 centimes\n %d piece de 5 centimes\n %d piece de 2 centimes\n %d piece de 1 centime", E_2,E_1,C_50,C_20,C_10,C_5,C_2,C_1); 
    
    
      
    
    }

    La fonction divise la somme par deux et récupère la valeur entière dans une variable E_2 puis à l'étape suivante associe la valeur de la somme moins le nombre de pièce de 2 euros à la somme. Il fait ça pour toutes les pièces. Cependant pour la valeur 7.85 la programme ne me retourne aucune pièce de 5 centimes et me retourne un total égal à 7.84. Le problème provient lors de la division de 0.0500 par 0.5f, il me retourne 0.9989. Je ne comprends pas. Avez-vous une explications ? 

    • Partager sur Facebook
    • Partager sur Twitter
      15 octobre 2019 à 19:59:18

      Bonjour ! C'est peut-être dû à l'imprécision des données de type 'float' : parfois, 0.05 vaut 0.0499999, et du coup si tu le divises par 0.05 ça peut en effet valoir un poil moins que 1.

      Une solution qui fait bricolage : ajouter une quantité strictement positive mais inférieure à 1 centime, du genre 0.0001, avant la division.

      Une solution qui marche peut-être mais qui laissera toujours un doute : utiliser des 'double'.

      Une solution probablement meilleure : fais tous les calculs en centimes avec des entiers. C'est seulement à la saisie et à l'affichage que tu remettras les valeurs en euros.

      -
      Edité par robun 15 octobre 2019 à 20:01:11

      • Partager sur Facebook
      • Partager sur Twitter
        15 octobre 2019 à 20:13:24

        Merci pour ta réponse ! J'avais pensé à faire tous les calculs en entier mais j'avoue que j'ai vite abandonné l'idée car je pensais être obligé de passer par des instructions conditionnelles mais en relisant ton message j'ai trouvé comment faire sans ! Merci beaucoup !
        • Partager sur Facebook
        • Partager sur Twitter
          15 octobre 2019 à 20:32:25

          Bonjour,

          En réalité l'erreur existe dès la première ligne car le nombres flottants sont stockées sous une approximation en binaire. Ainsi le float le plus proche de 7.85 est 7.849999904632568359375, et donc toutes tes opérations aboutiront au mieux au montant de 7.84. Si tu utilisais les double, il y aurait la même erreur car le double le plus proche est 7.8499999999999996447286321199499070644378662109375.

          Passer en arithmétique entière est une des méthodes les moins risquées, il suffit au moment de la conversion d'utiliser le correctif indiqué par robun. Ensuite tout est simple.

          int somme_en_centimes = (int)(somme*100.f + 0.5f); // on ajoute 0.5 centime pour un arrondi au plus proche des centimes
          int nb_2_francs = somme_en_centimes / 200;         // ensuite pas d'arrondi, pas de cast, plus que des nombres entiers
          somme_en_centimes -= nb_2_francs * 200;
          ... ... ...
          int nb_2_centimes = somme_en_centimes / 2;
          somme_en_centimes -= nb_2_centimes * 2;
          int nb_1_centime = somme_en_centimes;
          • Partager sur Facebook
          • Partager sur Twitter

          En recherche d'emploi.

            15 octobre 2019 à 22:26:33

            J'ai fait ces modifications et maintenant tout fonctionne ! Je vous remercie de m'avoir éclairé sur les problèmes d'arrondies :)
            void minPiece(float somme){ 
              somme *= 100.f;
              int E_2 = (int)(somme/200.f);
              somme = somme - (float)E_2*200.f;
              int E_1 = (int)(somme/100.f);
              somme = somme - (float)E_1*100.f;
              int C_50 = (int)(somme/50.f);
              somme = somme - (float)C_50*50.f;
              int C_20 = (int)(somme/20.f);
              somme = somme - (float)C_20 * 20.f;
              int C_10 = (int)(somme/10.f);
              somme = somme - (float)C_10 *10.f;
              int C_5 = (int)(somme/5.f);
              somme = somme - (float)C_5*5.f;
              int C_2 = (int)(somme/2.f);
              somme = somme - (float)C_2*2.f;
              int C_1 = (int)(somme/1.f);
              printf("Pour payer il vous faut :\n %d piece de 2 euros\n %d piece de 1 euro\n %d piece de 50 centimes\n %d piece de 20 centimes\n %d piece de 10 centimes\n %d piece de 5 centimes\n %d piece de 2 centimes\n %d piece de 1 centime", E_2,E_1,C_50,C_20,C_10,C_5,C_2,C_1); 
            
            
              
            
            }
            • Partager sur Facebook
            • Partager sur Twitter

            Problème étrange d'arrondie

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown