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 :

disfonctionnement floor avec double


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Juillet 2007
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 36
    Par défaut disfonctionnement floor avec double
    Bonjour,
    je voudrais créer un constructeur de fraction à partir d'un double.
    Voici le code en question :

    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
    ZFraction::ZFraction(double decimal)
    {
        int compteur(0);
     
     
        while(floor(decimal)!=decimal)
        {
     
            decimal*=10.0;
            compteur++;
        }
     
     
     
        m_numerateur=decimal;
        m_denominateur=pow(10.0,compteur);
     
     
        simplifier();
    }
    Quand je teste avec un double valant 0.401, la valeur de floor(decimal) vaut 400 au lieu de 401 quand j'arrive au troisième tour de boucle, ce qui est surprenant.
    Merci pour vos réponses.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Mai 2016
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2016
    Messages : 313
    Par défaut
    Bonjour
    0.401 n'a pas de représentation exacte en type 'double' (=IEEE-754 64 bits).
    Affiche les résultats successifs avec 17 chiffres de précision, et tu verras qu'à la troisième itération, decimal=400.99999...., produisant 400 par floor().
    C'est un problème de représentation des nombres et d'algorithme, la fonction floor() fonctionne correctement.

  3. #3
    Membre averti
    Inscrit en
    Juillet 2007
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 36
    Par défaut
    Mais comment palier à ce problème?
    Peut-être en convertissant le double en string, et en calculant le nombre de chiffres après la virgule?

  4. #4
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 966
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 966
    Par défaut
    Bonjour,
    Citation Envoyé par sgu35 Voir le message
    Mais comment palier à ce problème?
    Peut-être en convertissant le double en string, et en calculant le nombre de chiffres après la virgule?
    Tu ne peux pas éviter ce problème, dû à la représentation des flottants.

    Tu peux le réduire quand même en utilisant une bibliothèque muli-précision,
    la plus connue est GMP, je te laisse chercher, c'est facile à trouver.

    MAIS, ce n'est pas la panacée, ça ne fait que reculer le problème,
    tout en augmentant notablement le temps de calcul.

  5. #5
    Membre expérimenté
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Mai 2016
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2016
    Messages : 313
    Par défaut
    sgu35 :
    Tu peux en effet passer par des conversions en chaines de caractères, en contrôlant bien la précision, et laisser à la conversion standard le soin de gérer les arrondis.
    Mais ce n'est pas très élégant, surtout si le nombre provient à l'origine d'une saisie par l'utilisateur (conversion chaine -> double, et ensuite reconversion en chaine...).
    On peut aussi gérer explicitement les arrondis 'au plus proche', après avoir fixé une précison a priori, c'est souvent la méthode retenue : floor(400.999...) = 400, mais floor(400.999.... +0.5) = 401

    Mais le plus propre est de reconnaitre que 0.401 (par exemple) n'existe pas en double/IEEE-754, tout comme d'ailleurs la plupart des nombres non entiers que pourrait saisir un utilisateur, et manipuler directement la bonne représentation, c'est à dire en général une suite de chiffres décimaux dans une chaine de caractères.
    Ton constructeur devrait accepter et traiter une chaine.
    En entrée : chaine = aaaaa.ddddd
    Fractionner la chaine et convertir en deux entier n1=(aaaaa) et n2=(ddddd)
    Ensuite, traiter ces deux entiers, sans utiliser le type 'double'.
    Il faut bien sûr faire attention aux dépassements de capacité, traiter correctement les nombres négatifs si applicable, etc.
    On peut également définir une classe pour traiter directement les nombres en virgule flottante en représentation décimale, ça existe déjà certainement si tu ne veux pas le faire toi-même.

    Voir aussi les caractéristiques des différents types numériques, pour faire attention à la portabilité :
    http://www.cplusplus.com/reference/l...umeric_limits/

    Complément : vérifie quand même si ton compilateur favori implémente la nouvelle version de la norme IEEE-754 (2008), qui inclut les nombres décimaux. Ca parait être le cas en gcc, comme extension non standardisée (mais peut-être pas en C++).

  6. #6
    Membre averti
    Inscrit en
    Juillet 2007
    Messages
    36
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 36
    Par défaut
    Bonjour,
    j'ai utilisé des strings pour récupérer la partie décimale et la partie entière. Avec cela, le numérateur est correct, mais le dénominateur pose problème. En effet si on teste avec 0.32 ou 0.56, 10 à la puissance 2 retourne 99...

    Après quelques essais, j'ai trouvé que si je mettais 10.0000001 à la puissance n, pow retourne 100 pour ces double.
    J'ai aussi essayé de tester avec des double avec beaucoup de chiffres après la virgule mais il me met au maximum 6 chiffres après la virgule, peut-être est-ce qu'on atteint la limite de précision du langage c++.

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

Discussions similaires

  1. Problème étrange de précision avec double
    Par titoine1978 dans le forum DirectX
    Réponses: 4
    Dernier message: 22/02/2006, 09h26
  2. requete avec double jointure externe
    Par cdu dans le forum Langage SQL
    Réponses: 8
    Dernier message: 04/01/2006, 14h54
  3. requete avec double tri
    Par noarno dans le forum Access
    Réponses: 1
    Dernier message: 15/11/2005, 16h55
  4. [debutant][swt] CellEditor / CellModifier avec double clic
    Par antares24 dans le forum SWT/JFace
    Réponses: 2
    Dernier message: 10/05/2005, 02h25
  5. Réponses: 5
    Dernier message: 19/07/2004, 11h16

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