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 :

Problème calcul de taxes. Résultat erroné.


Sujet :

C++

  1. #1
    Candidat au Club
    Homme Profil pro
    Débutant en programmation C++
    Inscrit en
    Novembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Canada

    Informations professionnelles :
    Activité : Débutant en programmation C++
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2016
    Messages : 10
    Points : 3
    Points
    3
    Par défaut Problème calcul de taxes. Résultat erroné.
    Bonjour.

    Je débute en langage C++ et j'ai créé ce court programme qui calcule une taxe d'achat. Le montant de cette taxe est de 9.975%. Quand je calcule cette taxe et que je l'affiche j'obtiens le bon résultat mais aussitôt que j'additionne le montant entré à la taxe ça donne souvent de mauvais résultats.

    Par exemple: Si j'entre 100$ comme montant, ça me retourne 9,98$ de taxes ce qui est correct. Mais quand j'additionne 100 + 9,98 ça me retourne 109,97 et non 109,98. J'ai ajusté la précision à 2 en début de programme et je n'affiche que les 2 premiers chiffres après le point avec la commande fixed.

    Le problème je crois, c'est que je dois arrondir la taxe et l'affecter à une variable avant de l'additionner au montant entré. Ou bien alors je dois effectuer d'autres calculs pour obtenir le bon résultat. J'ai fais quelques recherches sur le sujet mais je n'ai pu trouver de solution simple et concrète et ça semble plus compliqué qu'il n'y parait au premier abord, car tout ce que j'ai vu sur le sujet jusqu'à présent c'est que les gens ont des manières différentes de répondre au problème. Et il semblerait que le langage C++ ne soit pas vraiment approprié pour ce genre de calcul.

    Voila le code de mon programme:

    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
    19
    20
    21
    22
    #include <iostream>
     
    int main() 
     
        {
              std::cout.precision (2);
     
    	  float montant;
              float taxe;
    	  float total;
     
    	  std::cout<<"Entrez le montant: ";
              std::cin >> montant;
              std::cin.ignore();
     
    	  taxe = montant * .09975;
    	  std::cout <<"Taxe: " << std::fixed << taxe << "\n";
    	  total = montant + taxe;	 
    	  std::cout <<"Total: " << std::fixed << total << "\n";
     
              return 0;
         }

  2. #2
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 565
    Points : 7 642
    Points
    7 642
    Par défaut
    Bonjour,

    Ce qui pose un problème c'est le type float qui est utilisé par de nombreux langages.
    Le type double améliorerait mais n'enlèverait pas le problème.
    Les nombres flottants ne sont pas des décimaux, en particulier 0.09975 contient une infinité de décimales en base 2 (au lieu de 5 en base 10); Le float ne peut stocker que 24 bits de précisions, le double 48 bits
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
                     en base 2 (24 bits de mantisse)                   soit en base 10    avec 2 décimales 
    0.09975 float  0.000110011000100100110111010...                     0.099749997...      0.10
    9.975  float   1001.11111001100110011001...                         9.97499974...       9.97
    109.975 float  111010.111111001100110011...                         109.974998...       109.97
    Après une addition des bits de précision peuvent être perdus. Après une multiplication par 10. ou 100. le dernier bit de précision change et on peut se retrouver avec une valeur légèrement supérieure au lieu d'inférieure ce qui explique le 9.98 qui peut parfois apparaître.
    Pour gérer des montants, les types float et double ne sont donc pas adaptés, il y aura toujours une erreur.
    On peut :
    * utiliser un librairie gérant des nombres décimaux (ils seront conformes à la base 10)
    * utiliser des nombres long long en travaillant en centimes, avec une division par 100 au moment de l'affichage (suffit pour des montants inférieurs à 92 233 720 368 547 758.07 !)
    * utiliser une librairie gérant les décimales fixes (basée sur des nombres entiers).
    * La STL C++ propose de travailler en long double contenant des centimes et affichés en Euros, dollars, ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    long double montant = 12.34LL * 100.LL + 0.1LL;  // pour $12.34, astuce ajouter 0.1 centime garanti l'arrondi supérieur
        std::cout.imbue( std::locale("en_US.utf8") ); // pour des dollars
        std::cout << std::put_money(montant) << '\n';

  3. #3
    Candidat au Club
    Homme Profil pro
    Débutant en programmation C++
    Inscrit en
    Novembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Canada

    Informations professionnelles :
    Activité : Débutant en programmation C++
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2016
    Messages : 10
    Points : 3
    Points
    3
    Par défaut
    Merci dalfab. En fait je veux reproduire ces résultats: http://www.calculconversion.com/calc...s-tps-tvq.html

    Le code que j'ai donné ici ne fait que calculer la TVQ et non la TPS pour que ce soit plus simple.

    Il ne semble pas y avoir de manière simple d'y parvenir et je n'arrive pas vraiment à comprendre et à appliquer le code que tu m'a donné.

  4. #4
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 565
    Points : 7 642
    Points
    7 642
    Par défaut
    L'exemple donné nécessite la dernière version C++ et ne doit toujours pas être disponible sous Windows.

    Il existe un moyen simple qui serait refusé dans une application certifiée.
    Les montants ont une erreur qui se situe souvent bien en dessous du centime. Cette erreur provoque une mauvaise estimation du dernier centime. En ajoutant 0.1 centime juste avant un affichage qui lui arrondira en centimes, on obtient un nombre correct.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    std::string pourAffMnt( double mnt ) { // arrondi 'proche' du dernier centime
       std::ostringstream sb;
       sb << std::setprecision(2) << std::fixed;
     
       if ( mnt > 0 )
          sb << mnt + 0.001;
       else if ( mnt < 0 )
          sb << mnt - 0.001;
       else
          sb << mnt;
       return sb.str();
    }
     
    std::cout << "montant : " << pourAffMnt( 100. * (1.+0.09975) ) << '\n';
    Si on doit vérifier que deux flottants sont égaux (pose un problème à cause des reports), on peut utiliser la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template< class T > inline bool quasi_egaux( T const & x , T const & y ) {
      return   std::abs( x - y ) < std::numeric_limits< T >::epsilon( ) * std::abs( x + y )
            || std::abs( x - y ) < std::numeric_limits< T >::min( );
    }
     
    if ( quasi_egaux( 100. * (1.+0.09975) , 109.975 ) )   // => vrai
    Cette fonction compare deux nombres et les considère égaux en ignorant les 2 derniers bits de mantisse.

  5. #5
    Candidat au Club
    Homme Profil pro
    Débutant en programmation C++
    Inscrit en
    Novembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Canada

    Informations professionnelles :
    Activité : Débutant en programmation C++
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2016
    Messages : 10
    Points : 3
    Points
    3
    Par défaut
    Merci pour les suggestions. Ajouter 0.001 donne souvent le bon résultat mais quelques fois, comme quand on entre le montant 100.29 on se retrouve avec un sous de plus dans le résultat. Il faut dire que j'utilise precision(2) et fixed qui affichent 2 chiffres seulement après le point mais qui semblent faire une sorte d'arrondissement de leur cru. Si je les utilise pas j'ai 3 chiffres ou plus après le point, ce que je ne veux pas, mais à ce moment les résultats semblent précis.

    Comment je fais pour avoir des résultats précis en affichant toujours seulement 2 chiffres après le point ?

  6. #6
    Candidat au Club
    Homme Profil pro
    Débutant en programmation C++
    Inscrit en
    Novembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Canada

    Informations professionnelles :
    Activité : Débutant en programmation C++
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2016
    Messages : 10
    Points : 3
    Points
    3
    Par défaut
    Je crois avoir trouvé une façon d'ajuster le résultat: Je n'utilise pas les setprecision et fixed et je n'additionne pas 0.001. Et si le troisième chiffre après le point est 5 ou plus j'augmente de 1 le chiffre directement a sa gauche. Apres pour ajuster le nombre de chiffres après le point à 2 seulement lors de l'affichage je sais pas trop comment ?

  7. #7
    Candidat au Club
    Homme Profil pro
    Débutant en programmation C++
    Inscrit en
    Novembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Canada

    Informations professionnelles :
    Activité : Débutant en programmation C++
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2016
    Messages : 10
    Points : 3
    Points
    3
    Par défaut
    Non, après quelques tests ma dernière méthode donne de mauvais résultats aussi. Il me semble que c'est impossible à faire, surtout avec des valeurs comme 9.975. Je crois que j'aurais plus de succès avec Java/Javascript.

  8. #8
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    La solution à ton problème est de ne pas utiliser de nombres à virgule flottante, comme l'a évoqué dalfab. Un float en C++ reste un float en Java.

  9. #9
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Pourquoi ne pas simplement utiliser des entiers ?
    C'est le seul moyen 100% sûr d'avoir des résultats corrects.
    Une troncature/division avant affichage et c'est réglé.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  10. #10
    Candidat au Club
    Homme Profil pro
    Débutant en programmation C++
    Inscrit en
    Novembre 2016
    Messages
    10
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Canada

    Informations professionnelles :
    Activité : Débutant en programmation C++
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Novembre 2016
    Messages : 10
    Points : 3
    Points
    3
    Par défaut
    Victoire ! J'ai réussi à faire ce que je voulais. J'ai programmé ceci pour la ligne de commande mais aussi en mode GUI avec Qt Creator et les 2 versions me donnaient les mêmes résultats erronés, mais plus maintenant ! J'ai trouvé ce qu'il fallait faire !

    Voila mon code pour le mode fenêtré de Qt Creator:

    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
    void MainWindow::on_lineEdit_textChanged(const QString &arg1)
    {
        double Montant = arg1.toDouble();
        double TPS = Montant * .05 + 0.005;
        double TVQ = Montant * .09975 + 0.005;
        int a = int(TPS);
        int b = int(TVQ);
        int TPS2 = (TPS-a)*100;
        int TVQ2 = (TVQ-b)*100;
        double c = ((double) TPS2)/100;
        double d = ((double) TVQ2)/100;
        ui->lineEdit_2->setText(QString::number(a+c, 'd' ,2));
        ui->lineEdit_3->setText(QString::number(b+d, 'd' ,2));
        ui->lineEdit_4->setText(QString::number(Montant+a+b+c+d, 'd' ,2));
    }
    Toutes ces manipulations sont nécessaires pour m'assurer d'avoir les bons résultats.

    Et voila de quoi a l'air cette fenêtre:

Discussions similaires

  1. Calcul de puissance au résultat erroné
    Par kafimma dans le forum C
    Réponses: 4
    Dernier message: 06/07/2016, 14h13
  2. Résultat du Calcul numéro de semaine erroné
    Par jerem7w dans le forum SQL
    Réponses: 2
    Dernier message: 07/09/2010, 13h38
  3. Problème calcul erroné avec sum()
    Par mouatte dans le forum Requêtes
    Réponses: 25
    Dernier message: 15/12/2008, 12h58
  4. Problème calcul de taxe
    Par hubald dans le forum ASP.NET
    Réponses: 2
    Dernier message: 13/11/2008, 01h53
  5. Problème pour afficher le résultat d'un calcul
    Par goomazio dans le forum Assembleur
    Réponses: 3
    Dernier message: 26/01/2006, 10h42

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