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

Java Discussion :

[Math]Problème troncage ou arrondi sur des valeurs


Sujet :

Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    55
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mars 2004
    Messages : 55
    Points : 62
    Points
    62
    Par défaut [Math]Problème troncage ou arrondi sur des valeurs
    Bonjour,
    J'ai un problème avec les variables de type double ou float, quand je fais des opérations mathématique il me donne des valeurs erronées (problème avec la mémoire ?) comme présenté dans le code :

    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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
       private void calcul() {
     
    //      double dValeur;
    //      double dArrondi;
    //      double dNombre;
     
          dValeur = 1260.05;
          dArrondi = 0.05;
          dNombre = 1;
          iType = 2;
          if (dNombre == 0) {
             iValeur = 0;
             fValeur = 0;
             dValeur = 0;
          } else {
             dValeur = dValeur / dArrondi * dNombre;
             System.out.println("Valeur avec un problème : " + dValeur);
             System.out.println("Valeur dValeur = 25200.9999999999996");
             System.out.println("au lieu de 25100 = 1260.05 / 0.05 * 1");
             if (iType == 0) {
                // Séparation par le millieu
                dValeur += 0.49999999;
             }
             if (iType == 1) {
                // Séparation par le suppérieur
                dValeur += 0.99999999;
             }
             if (iType == 2) {
                // Séparation par l'inférieur
                dValeur += 0;
             }
             iValeur = (int) dValeur;
             System.out.println("Valeur avec un problème : " + iValeur);
             System.out.println("iValeur devait me donner 25201");
             System.out.println("Mais iValeur me donne 25200, puisque dValeur = 25200.999999");
             iValeur = 25201;
     
             dValeur = iValeur * dArrondi / dNombre;
             System.out.println("Valeur avec un problème : " + dValeur);
             System.out.println("dValeur = 1260.0500000000002 aulieu de 1260.05");
             System.out.println("Calcul = 25201 * 0.05 / 1");
     
             iValeur = (int) dValeur;
             fValeur = (float) dValeur;
          }
       }
    Se qui me donne comme valeur en print :
    Valeur avec un problème : 25200.999999999996

    Valeur dValeur = 25200.9999999999996

    au lieu de 25100 = 1260.05 / 0.05 * 1

    Valeur avec un problème : 25200

    iValeur devait me donner 25201

    Mais iValeur me donne 25200, puisque dValeur = 25200.999999

    Valeur avec un problème : 1260.0500000000002

    dValeur = 1260.0500000000002 aulieu de 1260.05

    Calcul = 25201 * 0.05 / 1
    Est-ce que quelqu'un à une solution afin d'éviter ces reliquats de nombre qui polue ces chiffres.

    Merci beaucoup.


    Carrel :

  2. #2
    Membre éprouvé
    Profil pro
    Architecte technique
    Inscrit en
    Mars 2002
    Messages
    966
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mars 2002
    Messages : 966
    Points : 1 085
    Points
    1 085
    Par défaut
    C'est normal parceque le problème vient du fait que les float sont codés sur... je sais plus (32 ou 64 bits) donc il y à forcémment des arrondis pour représenter les nombres et tu pers des informations lors de calculs (nomamment multiplications et divisions)... donc pour pallier ce problème java propose la classe BigDecimal qui est une représentation plus exacte de nombres flottants et qui permets de faire des calculs "justes"... en quelques mots ils est déconseillé d'ultiliser les types natifs en java pour des calculs "complexes"... préférer BigDecimal à float ou double...

  3. #3
    Membre confirmé
    Avatar de Glob
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Avril 2002
    Messages
    428
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Suisse

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Avril 2002
    Messages : 428
    Points : 630
    Points
    630
    Par défaut
    Je confirme... il faut utiliser les BigDecimal.

    De plus (en tous cas sur mon JRE 1.3), il n'est pas toujours possible de créer un new BigDecimal(double) correct...

    Essayez d'imprimer un BigDecimal(71.05).toString()... surprise, la précision a déjà foutu le camp!

    Par contre, un BigDecimal("" + 71.05) (créé à partir du String forcé "71.05") donne bien 71.05...

    Quels résultats sur les derniers JRE?

    A méditer.
    Glob
    What would you do if you were not afraid?

    Cours et tutoriels pour apprendre Java , FAQ Java, et Forum Java

  4. #4
    Membre éprouvé
    Profil pro
    Architecte technique
    Inscrit en
    Mars 2002
    Messages
    966
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mars 2002
    Messages : 966
    Points : 1 085
    Points
    1 085
    Par défaut
    Une petite remarque sur la classe BigDecimal, il faut à tout prix éviter d'utiliser les méthodes floatValue() et doubleValue() qui renvoient le BigDecimal sous forme de double ou de float, donc en provoquant des arrondis...

    Manipuler les BigDecimal soit sous forme de BigDecimal, ou sois sou forme de chaîne de caractère pour affichage et formatage et rien d'autre...

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    55
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mars 2004
    Messages : 55
    Points : 62
    Points
    62
    Par défaut
    Je vous remercie pour vos réponses, je constate qu'aucune solution n'est vraiment satisfaisant, je trouve dommage que Java et d'autres languages (VB 6) ne résolvent pas ce problème dans les variables natives.

    Je vais résoudre mon point en ajoutant une fonction qui va me traduire, avec un certain nombre de décimale la valeur à retourner (en espérant que j'il n'y ait pas d'exception)

    Voici le code que j'ai préparé :
    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
    23
    24
    25
    26
    27
    28
    29
    30
     
       public double retValeur(double dVal, int iNbDec) {
          String sVal = Double.toString(dVal);
          String sDim[] = sVal.split("[.]");
          if (sDim.length > 1) {
             String sRet = "0";
             if (sDim[1].length() > iNbDec) {
                String sDec = sDim[1].substring(0, iNbDec);
                int iDec = Integer.parseInt(sDec);
                char s = sDim[1].charAt(iNbDec);
                if (s > '4') {
                   iDec++;
                }
                sDec = iDec + "";
                int iNombreCaractere = iNbDec - sDec.length();
                if (iNombreCaractere < 0) {
                   // Ajouter un à l'entier
                   int iEnt = Integer.parseInt(sDim[0]) + 1;
                   sRet = iEnt + "";
                } else {
                   sRet = sDim[0] + "." + "0000000".substring(0, iNbDec - sDec.length()) + sDec;
                }
             } else {
                sRet = sDim[0] + "." + sDim[1];
             }
             return Double.parseDouble(sRet);
          } else {
             return dVal;
          }
       }
    Merci pour vos renseignements.

    Carrel

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    50
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 50
    Points : 36
    Points
    36
    Par défaut
    Citation Envoyé par thibaut
    Une petite remarque sur la classe BigDecimal, il faut à tout prix éviter d'utiliser les méthodes floatValue() et doubleValue() qui renvoient le BigDecimal sous forme de double ou de float, donc en provoquant des arrondis...

    Manipuler les BigDecimal soit sous forme de BigDecimal, ou sois sou forme de chaîne de caractère pour affichage et formatage et rien d'autre...
    bump !
    Ca m'a sauvé la vie là !

  7. #7
    Futur Membre du Club
    Inscrit en
    Mai 2009
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 18
    Points : 9
    Points
    9
    Par défaut
    Petit exemple pratique (qui m'a tout de même bien embêté):
    => new BigDecimal("1.0550") = 1.0550
    => new BigDecimal(1.0550) = 1.0549999999999999378275106209912337362766265869140625

    Alors effectivement c'est assez proche et pourtant, faite:
    1) 95 * 1.0550 (cas d'une TVA à 5.5%) = 100.225
    2) 95 * 1.0549999999999999378275106209912337362766265869140625 = 100.2249999999999940936135089941672049462795257568359375

    Faites maintenant un arrondi pour passer en euro et vous obtenez:
    1) 100.23
    2) 100.22 !!

    Moralité merci pour l'astuce de passer une chaine de caractère au lieu d'un float !

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

Discussions similaires

  1. Calculs sur des valeurs d'énumérés
    Par Tic_et_Tac dans le forum Ada
    Réponses: 3
    Dernier message: 20/05/2008, 23h58
  2. [XSL] Opération sur des valeurs XML grâce à Javascript
    Par kimar dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 26/06/2007, 12h57
  3. count sur des valeurs de champs
    Par Braillane dans le forum Langage SQL
    Réponses: 2
    Dernier message: 23/05/2007, 16h27
  4. Quotes sur des valeurs numériques
    Par shadeoner dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 05/05/2006, 14h56
  5. "Order by" sur des valeurs spécifiques
    Par damienTrax dans le forum Requêtes
    Réponses: 2
    Dernier message: 23/11/2004, 09h20

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