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 :

Conversion de string en double avec une précision supérieure à 4 décimaux


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2010
    Messages
    139
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 139
    Points : 48
    Points
    48
    Par défaut Conversion de string en double avec une précision supérieure à 4 décimaux
    Bonjour,

    Je souhaite récupérer un double par l'intermédiaire d'une chaine de caractère (string). mon double est de la forme 49.123400005.
    La réception du string se passe sans soucis, mais lorsque je veux mettre cette information dans une variable de type double, ma valeur se voit tronquée à 4 décimaux, et je n'ai plus que la valeur 49.1234. J'ai essayé différentes manières de faire ma conversion (toutes ont le même résultat) :

    - Avec les istringstream :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    double convertStringToDouble(string strVal)
    {
    	istringstream iss(strVal);
    	double dReturn;
    	iss >> dReturn;
    	return dReturn;
    }
    -Avec la fonction atof :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    dVal = atof(dataRead.c_str());
    - Avec la fonction strtod :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char * tmp;
    dVal = strtod(dataRead.c_str(), &tmp);
    Si quelqu'un sait pourquoi, et sait s'il y a un moyen de récupérer la précision attendu, je suis preneur.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour,

    C'est étrange : chez moi le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    double convertStringToDouble(string strVal)
    {
    	istringstream iss(strVal);
    	double dReturn;
    	iss >> dReturn;
    	return dReturn;
    }
    me retourne un dReturn contenant 49.123400005000001.

    Es-tu sûr d'avoir fait un test correct?

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Février 2010
    Messages
    139
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 139
    Points : 48
    Points
    48
    Par défaut
    Oui je suis sûr, dans ma fonction je fais l'affichage de mon string pour m'assurer que j'ai la bonne information à convertir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    double convertStringToDouble(string strVal)
    {
    	istringstream iss(strVal);
    	double dReturn;
    	iss >> dReturn;
            cout << strVal;
            cout << dReturn;
    	return dReturn;
    }
    Ne serait-ce pas dû aux éventuelles différences de plate forme ? Sinon, une solution consisterait à multiplier par 1 000 000 ma valeur, dans la string (avant de l'y placer), puis après l'avoir convertie en int, la diviser par 1 000 000 et la mettre dans un double. Mais cette solution contourne un peu mon problème...

  4. #4
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    C'est votre méthode de test qui n'est pas bonne.
    Il faut dire à quelle précision vous souhaitez afficher vos nombres :
    http://www.cplusplus.com/reference/i...ase/precision/

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 047
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 047
    Points : 12 074
    Points
    12 074
    Par défaut
    Le problème n'est pas une troncature mais la limitation dans la représentation des nombres par un double.

    Vous aurez des erreurs d'arrondie aussi bien avec des grands nombres qu'avec des petits nombres. Et les erreurs sur les grands nombres sont plus grandes que sur les petits nombres.

    Plus vous faites d'opérations et plus la différence d'échelles entre les opérandes de ces opérations sont grandes plus il y a d'approximation.
    Donc, la tambouille X 1xxxx / 1xxxx est à éviter.

    Il faut aussi prendre en compte que les routines d'affichage tronquent l'affichage sans que le nombre le soit.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Pour vérifier votre nombre, faites par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf(" le nombre en double %0.10f\n",nombre);

  7. #7
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Citation Envoyé par bacelar Voir le message
    Et les erreurs sur les grands nombres sont plus grandes que sur les petits nombres..


    Citation Envoyé par bacelar Voir le message
    Plus vous faites d'opérations et plus la différence d'échelles entre les opérandes de ces opérations sont grandes plus il y a d'approximation.


    Accuracy and Stability of Numerical Algorithms

  8. #8
    Invité
    Invité(e)
    Par défaut
    Ce serait sympa de citer le paragraphe, ou au moins indiquer le chapitre.

  9. #9
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Ce serait sympa de citer le paragraphe, ou au moins indiquer le chapitre.
    Paragraphe 1.19, points 5 et 6, entre autres...

  10. #10
    Invité
    Invité(e)
    Par défaut
    Je pense que ce qu'Alef69 veut dire, c'est si on multiplie X par 1.En (lire 1 multiplié par 10 puissance n), on ajoute n à sa caractéristique, et on ne touche pas à la mantisse. (probablement)
    Par contre, si on le multiplie par 10000.00, moi, je ne sais pas exactement ce qui se passe.
    Mais dans l'absolu, je pense aussi que, sauf raison précise, faire X = X*10000/10000 est à éviter.
    me retourne un dReturn contenant 49.123400005000001.
    Question est-ce que 49.123400005000001 == 49.123400005 ?

  11. #11
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Citation Envoyé par Pierre Dolez Voir le message
    Je pense que ce qu'Alef69 veut dire
    Ne pensez pas à ma place, lisez : vous m'avez demandé des précisions, je vous les ai données.

    Citation Envoyé par Pierre Dolez Voir le message
    Question est-ce que 49.123400005000001 == 49.123400005 ?

  12. #12
    Invité
    Invité(e)
    Par défaut
    Bonsoir,
    J'ai lu mais pas très bien compris le langage de vos deux smiles.
    Pour les autres membres qui n'auraient pas compris non plus, je faisais allusion à un sujet très controversé sur la comparaison de flottants. Je ne cherche en aucun cas à ré-ouvrir le débat, mais pardonnez-moi, l'occasion était trop belle et trop tentante.
    Par ailleurs, je suis débutant et j'apprends. Donc j'aurais pu dire aussi "comment se fait-il qu'on lit une valeur qui est 49.123400005 et que l'on obtient un résultat qui est 49.123400005000001" ?
    Bonne soirée.

  13. #13
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    l'affichage par cout fait un fatras pas possible et n'est pas valdie comme verification. Vérifier les patterns de bits.

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Février 2010
    Messages
    139
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 139
    Points : 48
    Points
    48
    Par défaut
    En faite, j'ai utilisé un Log4j pour mon affichage, j'ai mis un cout parce que c'est plus rapide à utiliser dans un exemple.

  15. #15
    Invité
    Invité(e)
    Par défaut
    Donc la vérification serait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if (dReturn == 49.123400005)
        ....
    Pardon pour mon ignorance, c'est quoi un Log4j ?

  16. #16
    Membre du Club
    Profil pro
    Inscrit en
    Février 2010
    Messages
    139
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 139
    Points : 48
    Points
    48
    Par défaut
    C'est un framework Apache pour voir les traces d'une exécution logicielle. Enfin c'est plutôt log4cxx que j'utilise, log4j étant pour les programmes en langage Java. Si ça se trouve, il présente la même particularité que cout...

  17. #17
    Invité
    Invité(e)
    Par défaut
    Dans l'impression générée pas le cout, le 1 est en 17ème position (si j'ai bien compté).
    Or, la précision d'un double est de 15 chiffres. Donc, il n'y a aucune raison que le 17è soit bon.
    Je ne sais pas le "fatras" que fait un cout, mais le résultat est logique : les 15 premiers chiffres sont bons.
    Ceux qui l'ont essayé ont vérifié que le test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if (dReturn == 49.123400005)
        ....
    est bon

  18. #18
    Membre habitué Avatar de nowahn
    Homme Profil pro
    Inscrit en
    Août 2008
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 84
    Points : 150
    Points
    150
    Par défaut
    Bonjour,

    Pour recentrer la discussion sur le problème initial de K-you (le 1 en 17ème position est une erreur d’arrondi inhérente au caractère « flottant » d’une discussion sur un forum , le problème initial est le 5 en 11ème position, qui rentre dans la précision d’un double, en tout cas sur mon Mandriva 64 bits).

    Tu dois faire l’affichage comme ceci pour vérifier :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    cout << precision(11) << dReturn;
    car une précision de 6 est utilisée par défaut (je crois), ce qui coupe sont nombre en plein milieu des zéros et t’affiche une valeur tronquée, même si la variable contient bien la valeur complète.

    Après, je connais pas Log4j ou log4cxx, je sait pas à quelle précision ça affiche la variable par défaut.

    Si après une vérification correcte, la variable contient vraiment la valeur tronquée, c’est que c’est l’opération
    qui pose problème. mais je ne crois pas que l’opérateur >> utilise de précision par défaut, je pense qu’il utilise tous les chiffres qu’il trouve en entrée, non ?

  19. #19
    Membre expérimenté
    Homme Profil pro
    Chercheur
    Inscrit en
    Mars 2010
    Messages
    1 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur

    Informations forums :
    Inscription : Mars 2010
    Messages : 1 218
    Points : 1 685
    Points
    1 685
    Par défaut
    Bonjour,

    Citation Envoyé par Pierre Dolez Voir le message
    Donc j'aurais pu dire aussi "comment se fait-il qu'on lit une valeur qui est 49.123400005 et que l'on obtient un résultat qui est 49.123400005000001" ?
    Lorsqu'on écrit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    double dReturn = 49.123400005;
    on demande une représentation flottante à la précision double de 49.123400005.
    Cette question a été récemment traitée dans une autre discussion :
    http://www.developpez.net/forums/d96...n-long-double/

    Le lien qui vous intéresse est celui donné par Joel F.

    Notez qu'il se passe exactement la même chose pour le test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if (dReturn == 49.123400005)
    ...
    i.e. que l'on compare dReturn à la représentation flottante en précision double de 49.123400005.
    Ma machine représente ce nombre avec le flottant 49.123400005000001.

    En résumé, il ne faut pas confondre ce que vous écrivez dans votre éditeur de texte et le code généré à partir de celui-ci.
    Personne ne vous empêche d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    float a = 9.99999999999999999999999999999999999999999999999999999;
    mais ce n'est pas pour autant que a contiendra exactement ce que vous avez écrit dans le membre de droite de votre égalité.

  20. #20
    Invité
    Invité(e)
    Par défaut
    i.e. que l'on compare dReturn à la représentation flottante en précision double de 49.123400005.
    Ma machine représente ce nombre avec le flottant 49.123400005000001.
    FAUX
    Votre machine représente un flottant en précision double, c'est à dire sur 64 bits un nombre avec une précision de 15 chiffres, quelle que soit la position du point décimal.
    Si vous affichez plus de chiffres significatifs, les chiffres supplémentaires seront n'importe quoi, et je pense dépendront de la plateforme, de l'OS.
    J'ai apporté une réponse précise dans le lien de lien de lien que vous m'avez donné.

Discussions similaires

  1. [VB.NET] Conversion de String en Double
    Par JB-Tech dans le forum Windows Forms
    Réponses: 9
    Dernier message: 26/02/2018, 08h32
  2. Réponses: 2
    Dernier message: 09/02/2015, 11h02
  3. Réponses: 9
    Dernier message: 19/04/2013, 17h46
  4. Conversion d'un String en Double dans une JSP
    Par demcoul dans le forum Servlets/JSP
    Réponses: 4
    Dernier message: 18/04/2012, 19h00
  5. [Source] Comment arrondir un nombre avec une précision variable
    Par OhMonBato dans le forum Vos contributions VB6
    Réponses: 2
    Dernier message: 31/03/2007, 13h44

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