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

Langage Java Discussion :

Arrondi commercial problématique


Sujet :

Langage Java

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 5
    Par défaut Arrondi commercial problématique
    Salut !

    Ma question est simple : comment réaliser un arrondi commercial d'un "double" à deux chiffres après la virgule ? Ou plutôt : pourquoi ma solution ne fonctionne pas correctement ?


    J'avais d'abord pensé à ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public static double arrondi(double somme)
      {
        return ((double) Math.round(somme * 100)) / 100;
      }

    Problème :
    Voici une utilisation de cette fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public static void main(String args[])
      {
        double total = 1000, interets = 0, interets_arrondis = 0;
        for (int annee = 1; annee <= 10; annee++)
        {
          interets = total * 0.05;
          interets_arrondis = arrondi(interets);
          total += interets_arrondis;
     
          System.out.println("Après " + annee + " année(s) => intérêts : " + interets + " - arrondi : " + interets_arrondis + " - total : " + total);
        }
      }
    et son effet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Après 1 année(s) => intérêts : 50.0 - arrondi : 50.0 - total : 1050.0
    Après 2 année(s) => intérêts : 52.5 - arrondi : 52.5 - total : 1102.5
    Après 3 année(s) => intérêts : 55.125 - arrondi : 55.13 - total : 1157.63
    Après 4 année(s) => intérêts : 57.88150000000001 - arrondi : 57.88 - total : 1215.5100000000002
    Après 5 année(s) => intérêts : 60.775500000000015 - arrondi : 60.78 - total : 1276.2900000000002
    [...]
    On voit que tout se passe comme prévu jusqu'à la 4ème année, mais après le comportement devient plus étrange. A la quatrième année, l'arrondi est bien fait (57.88150000000001 => 57.88) mais quand on ajoute cet arrondi à une autre somme, on obtient pas le bon résultat : 1157.63 + 57.88 = 1215.5100000000002...

    J'imagine que c'est une histoire de représentation machine des décimaux ou un truc comme ça... Quelqu'un pourrait-il m'expliquer ce qui se passe plus en détail ? Merci d'avance !

  2. #2
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster ;) (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag :resolu:

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 5
    Par défaut
    Merci. Mais ce n'est pas tellement trouver une autre manière de faire cet arrondi qui m'interesse, c'est surtout COMPRENDRE pourquoi ma solution ne fonctionne pas...

  4. #4
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Par défaut
    Cela vient de la façon dont sont représentés les doubles en mémoire. En effet ceux-ci sont ce que l'on appelle des nombres à virgule flottante, c'est-à-dire un nombre dans lequel la position de la virgule n'est pas fixe, et est repérée par une partie de ses bits (appelée l'exposant), le reste des bits permettent de coder le nombre sans virgule (la mantisse).
    Cela entraine une imprecision sur le nombre, c'est d'ailleur pourquoi il ne faut pas utiliser les doubles (ni les floats) pour faire du calcul de précision.
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster ;) (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag :resolu:

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 5
    Par défaut
    Du calcul de précision à deux chiffres après la virgule...

    Un autre exemple d'utilisation de l'arrondi pour voir à quel point c'est bizarre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public static void main(String args[])
      {
        System.out.println(0.61 + arrondi(57.88150000000001));
        System.out.println(0.62 + arrondi(57.88150000000001));
        System.out.println(0.63 + arrondi(57.88150000000001));
        System.out.println(0.64 + arrondi(57.88150000000001));
        System.out.println(0.65 + arrondi(57.88150000000001));
        System.out.println(0.66 + arrondi(57.88150000000001));
        System.out.println(0.67 + arrondi(57.88150000000001));
        System.out.println(0.68 + arrondi(57.88150000000001));
        System.out.println(0.69 + arrondi(57.88150000000001));
      }
    donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    58.49
    58.5
    58.510000000000005
    58.52
    58.53
    58.54
    58.550000000000004
    58.56
    58.57

  6. #6
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Par défaut
    Les 0.000000000000005 et 0.000000000000004 en trop sont le résultat de l'imprécision inhérente aux nombres à virgule flottante.

    Etant donné que tu veux une précision à deux décimales, cela ne posera aucun problème dans tes calculs (dans ton cas l'imprécision est négligeable).

    Le seul problème pour toi vient à l'affichage car si tu affiche un double tel quel et qu'il contient une imprécision, alors celle-ci sera aussi affichée.

    C'est pourquoi tu dois passer par un DecimalFormat pour n'afficher que les deux premières décimales.
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster ;) (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag :resolu:

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  7. #7
    Membre chevronné Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Par défaut
    Peut être faut-il préciser à notre ami que tous ces problèmes sont résolus avec BigDecimal.

    (ou quasiment résolus...).

  8. #8
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par spekal
    Peut être faut-il préciser à notre ami que tous ces problèmes sont résolus avec BigDecimal.

    (ou quasiment résolus...).
    Uniquement si les calculs sont décimaux, mais si par exemple tu fais 1 divisé par 3, BigDecimal va râler si tu ne lui indiques pas une précision maximale à ne pas dépasser...

  9. #9
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Par défaut
    Citation Envoyé par spekal
    Peut être faut-il préciser à notre ami que tous ces problèmes sont résolus avec BigDecimal.

    (ou quasiment résolus...).
    Etant donné que ce problème d'imprécision des doubles est négligeable dans ses calculs (il veut une précision de deux décimales), il n'y a aucun intérêt à utiliser BigDecimal car sont utilisation est beaucoup plus couteuse en ressource.
    BigDecimal est à réserver pour les calculs de précision (du calcul à deux décimales n'est pas ce que l'on peut appeler du calcul de précision).

    Son seul problème étant l'affichage, la solution la plus appropriée est celle du DecimalFormat.
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster ;) (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag :resolu:

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  10. #10
    Membre chevronné Avatar de spekal
    Inscrit en
    Mai 2005
    Messages
    502
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 502
    Par défaut
    Je ne suis pas d'accord. La quantité de décimales ne veut rien dire quant à la précision. Il y a des tas de gens qui veulent à tout prix que 20/3 fasse 0,67, et pas 0,666, ou 0,66 ou je ne sais quoi d'autre. Ils te diront sûr d'eux que 0,67 c'est très précis, tandis que 0,666, ça ne l'est pas. Ce n'est pas scientifique, mais c'est comme ça. On peut très bien vouloir faire du calcul de précision, à deux décimales, et du calcul à 36 décimales imprécis. Je n'en sais rien à priori, et c'est pour ça qu'il me semblait utile de le préciser. C'était une précision à une décimale, d'accord, mais une précision quand même. Quand au coût en ressources de BigDecimal, il y a largement pire.

  11. #11
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Par défaut
    Les arrondis suivent quand même une certaine convention.
    Ainsi pour 6.66X,
    si 0 <= X < 5 alors 6.66
    si 5 <= X <= 9 alors 6.67

    Donc par convention 6.666 arrondit à deux décimales donne 6.67, chose que respecte la classe DecimalFormat.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    DecimalFormat df = new DecimalFormat("########.00");
    System.out.println(df.format(6.664));
    System.out.println(df.format(6.666));
    affiche
    6.66
    6.67
    Citation Envoyé par spekal
    Quand au coût en ressources de BigDecimal, il y a largement pire
    Certes, mais si tu as beaucoup de calculs, cela peut se ressentir.
    Donc si tu n'as pas le choix ok, mais si tu peut t'en passer c'est mieux (et c'est le cas ici ).
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster ;) (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag :resolu:

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  12. #12
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 194
    Par défaut
    Citation Envoyé par cowek
    Du calcul de précision à deux chiffres après la virgule...

    Un autre exemple d'utilisation de l'arrondi pour voir à quel point c'est bizarre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public static void main(String args[])
      {
        System.out.println(0.61 + arrondi(57.88150000000001));
        System.out.println(0.62 + arrondi(57.88150000000001));
        System.out.println(0.63 + arrondi(57.88150000000001));
        System.out.println(0.64 + arrondi(57.88150000000001));
        System.out.println(0.65 + arrondi(57.88150000000001));
        System.out.println(0.66 + arrondi(57.88150000000001));
        System.out.println(0.67 + arrondi(57.88150000000001));
        System.out.println(0.68 + arrondi(57.88150000000001));
        System.out.println(0.69 + arrondi(57.88150000000001));
      }
    donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    58.49
    58.5
    58.510000000000005
    58.52
    58.53
    58.54
    58.550000000000004
    58.56
    58.57
    Il y a encore un truc qui va te défriser encore un peu plus
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    System.out.println(.63+57.88);
    affiche :
    58.510000000000005
    La solution à ton problème, oui il y a en a une :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public static double arrondi(double d) {
         return Math.rint(d);
    }
    [EDIT] J'ai revérifié, Math.rint(d) ne fait pas ce que je pensais, la méthode se contente de faire (long)d

  13. #13
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Par défaut
    Citation Envoyé par had35
    Il y a encore un truc qui va te défriser encore un peu plus
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    System.out.println(.63+57.88);
    affiche :
    58.510000000000005
    As tu lu mes messages précédents ? J'y ai expliqué ce comportement.

    Citation Envoyé par had35
    La solution à ton problème, oui il y a en a une :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public static double arrondi(double d) {
         return Math.rint(d);
    }
    As tu lu ce que voulait cowek ? DEUX DECIMALES, or la méthode Math.rint() arrondi à l'entier.

    Faut lire les messages avant de poster
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster ;) (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag :resolu:

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  14. #14
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 194
    Par défaut
    Citation Envoyé par le y@m's
    Faut lire les messages avant de poster
    C'est pas ma faute m'sieur c'est mes yeux qui boudent mon cerveau

  15. #15
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 5
    Par défaut
    Merci à vous tous pour vos réponses.
    En fait le problème que j'ai eu était posé dans le cadre d'un T.D. d'initiation à java de mon école. L'objectif était de réaliser un système informatique pour une banque (gestion des clients et des comptes)...
    Et j'avais besoin d'un arrondi une fois que j'avais calculé les intérêts d'une année, avant de les capitaliser.

    Donc en conclusion, l'erreur réalisée n'est à priori pas très importante et j'ai utilisé DecimalFormat pour l'affichage (merci à le y@m's de me l'avoir fait découvrir). En fait, l'erreur pourrait devenir visible si notre banque (virtuelle ) se pereinise et commence à traiter des comptes avec beaucoup de chiffres . Donc pour faire pro, il faudrait utiliser BigDecimal (eh oui, les clients les plus riches sont les plus pingres : ils iront peut-être chipoter pour l'écart de 1 centime qui apparaitra au bout de 100 ans ). Mais bon... Notre prof nous a dit d'aller au plus simple. Elle avait précisé que, déjà, le calcul des intérêts c'était pour ceux qui avaient fini avant l'heure, alors ne parlons même pas de ces problèmes d'arrondi. Moi, vu que je suis un gros fayot lèche-bottes j'ai avancé, mais bon faut quand même pas abuser !

    J'ai eu mes réponses, alors j'appuie sur le bouton "résolu" !

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

Discussions similaires

  1. [Math]Problème troncage ou arrondi sur des valeurs
    Par Carrel dans le forum Général Java
    Réponses: 6
    Dernier message: 07/10/2009, 16h11
  2. [BigDecimal] les arrondis...
    Par LoulouFifi dans le forum API standards et tierces
    Réponses: 3
    Dernier message: 13/01/2004, 19h37
  3. création d'un bouton de forme arrondie
    Par THIERRY L. dans le forum C++Builder
    Réponses: 2
    Dernier message: 15/12/2003, 15h04
  4. Sauvegarde problématique sous excel par OLE
    Par ulysse66x dans le forum API, COM et SDKs
    Réponses: 2
    Dernier message: 16/04/2003, 22h23
  5. [VB6] Racine carrée + arrondi
    Par Krys29 dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 28/10/2002, 14h19

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