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 :

Float et double imprécis..


Sujet :

C++

  1. #1
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2007
    Messages
    123
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2007
    Messages : 123
    Par défaut Float et double imprécis..
    Bonjour,

    Je rencontre un problème gênant, je trouve que les float et les double ne sont pas assez précis dans le sens où si j'initialise une variable à 0.01 par exemple, et bien en réalité, le contenu de la variable sera quelque chose du genre 0.00999998 (pas toujours, je l'accorde). Cela me gène car j'ai besoin de faire des calculs très précis. J'ai besoin de récupérer 0.01 et pas 0.00999998 !

    J'ai essayé de faire une méthode d'arrondi, mais cela ne change rien au problème.

    Auriez-vous une solution ?

  2. #2
    screetch
    Invité(e)
    Par défaut
    0.01 n'est pas représentable parfaitement en base 2. Tu peux utiliser une bibliothèque qui représente les floats en base 10 (et donc faire du calcul en software) ce qui sera lent et ne pourra de toutes facons pas représenter 1/3 non plus.

  3. #3
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2007
    Messages
    123
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2007
    Messages : 123
    Par défaut
    Dans mon cas, je cherche à obtenir le plus proche multiple d'une valeur à partir d'une variable.
    Par exemple, j'ai 0.21, et je veux le multiple immédiatement supérieur de 0.05 donc le résultat serait 0.25

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    float time = 0.21;
    float epsilon = 0.0000001
    float remainder = (fabs(time)/0.05)-floor(fabs(time)/0.05);
    while (remainder>epsilon) {
    	time+=0.01;
    	remainder = (fabs(time)/0.05)-floor(fabs(time)/0.05);
    }
    Ce code fonctionne sauf lorsque j'ai une valeur approximative genre 0.249999999 au lieu de 0.25... Ce qui pose problème

  4. #4
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 614
    Par défaut
    Pas de solution à part utiliser des tolérances un peu partout.

    Après, à toi de te demander ce que tu appel des calcules "précis". Un float te donne en gros 6 chiffres signification en base 10, un double 16.

    As-tu réellement besoin d'avoir plus de 16 chiffres significatif ? En d'autre thermes, as-tu réellement besoin de connaitre le nombre d'atome sur terre, à l'atome près ?

    Il n'y a quasiment aucune application pratique nécessitant une tel précision. Si tu en a vraiment besoin, il existe des lib qui peuvent te donner plusieurs centaines de chiffres significatif (mpfr par ex. http://www.mpfr.org/, voir travailler vraiment en réel (tu pourra alors vraiment écrire "1/3" ou sqrt(2) ), mais je te les déconseille car cela alourdit énormément le programme et rend le développement plus complexe.

    Il est en général plus simple de revoir l'algo pour limiter les erreurs d'arrondit que de sortir le lance roquette en utilisant ce genre de lib

  5. #5
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2007
    Messages
    123
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2007
    Messages : 123
    Par défaut
    Je ne peste pas sur le nombre de chiffres après la virgule mais bien sur leur précision comme dit plus haut, je ne cherche pas à avoir 12 ou 25 chiffres après la virgule mais bien des nombres "ronds", 0.25 et pas 0.24999998

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Ce n'est pas un problème de précision mais de représentation.
    Ne pas utiliser des float/double mais une bibliothèque en virgule fixe (ou entier+scalaire si le besoin est simple et bien maîtrisé)

  7. #7
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 614
    Par défaut
    0.25 n'est pas "mathématiquement" plus précis que 0.249999999 avec une précision float.

    Si c'est pour afficher le résultat, à toi de l'arrondir à la main à la 2ème ou 3ème décimal (printf("%.2f", value), je me souvient plus comment on fait avec std::cout mais c'est quelque part dans la faq de développez )

    Si c'est pour l'utiliser après, tu doit faire de la bidouille du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if ( fabs(value - 0.25) < epsilon )
    Si tu tient absolument à avoir la valeur exacte, tu doit passer en arithmétique entière (multiplie par le nb de décimales, caster en int, trouver le multiple, rediviser par le nb de décimal. Et encore, la dernière division risque de créer le même problème...), ou utiliser une lib externe comme l'a dit 3DArchi.

    Dans tous les cas c'est pas simple

  8. #8
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2007
    Messages
    123
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2007
    Messages : 123
    Par défaut
    Je vous donne le bout de code, vous comprendrez mieux.
    Je cherche à trouver le multiple (le plus proche immédiatement supérieur de time) du step que j'ai calculé en fonction du range que j'ai trouvé.

    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
    float min = GetMinValue();
    float max = GetMaxValue();
    float range = max-min;
    float step = 0.0;
     
    int precision = -3;
    float power;
    while (!step)
    {
    	power = pow(10.0, precision);
    	if (range <= 1.0*power+power/100) {
    		step = 0.1*power;
    	}
    	else if (range <= 2.0*power+power/100) {
    		step = 0.2*power;
    	}
            else if (range <= 5.0*power+power/100) {
                    step = 0.5*power;
    	}
    	else { 
    		precision++;
    	}
    }
     
    precision--;
     
    float time = min;
    time = RoundUp(time, precision);
     
    float remainder = (fabs(time)/step)-floor(fabs(time)/step);
    while (remainder>0.0001) {
    	time+=0.1*power;
    	remainder = (fabs(time)/step)-floor(fabs(time)/step);
    }

  9. #9
    screetch
    Invité(e)
    Par défaut
    tu pourrais multiplier (par 100, 1000 ou quelque chose)
    passer en entiers
    faire tes calculs exacts
    rediviser

    tu obtiendras la représentation binaire la plus proche que la machine peut avoir.

    Mais ca ne fera pas de miracles; ca ne fera pas par exemple qu'un nombre qui n'est pas représentable en binarie devienne correct.

  10. #10
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2007
    Messages
    123
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2007
    Messages : 123
    Par défaut
    Oui, passer avec des calculs d'entiers ne règlera pas le problème, lors de la dernière division, le problème réapparaitra.
    Je pense que je vais utiliser des tolérances un peu partout comme suggéré plus haut.

  11. #11
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 614
    Par défaut
    Et si tu passait tout en entier ?
    Apparemment, c'est pour utiliser du temps. S'il est en seconde, tu pourrais le passer en ms et n'utiliser que des entiers.

  12. #12
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2007
    Messages
    123
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2007
    Messages : 123
    Par défaut
    Je ne peux pas tout passer en entiers, je dois respecter les valeurs comme elles sont.
    C'est du temps en l’occurrence mais cela pourrait être autre chose.

  13. #13
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 965
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 965
    Par défaut
    Qia,

    Ça ne t'empêche pas d'utiliser des entiers, il suffit de faire les fonctions nécessaires pour la saisie et l'affichage des valeurs.

    Sinon, ton problème est strictement insoluble, c'est la représentation des réels qui est en cause, et c'est irréductible, quels que soient les moyens utilisés, puisqu'il y a une infinité de réels entre deux réels distincts, aussi proche soient-ils (pour ceux qui vont préconiser d'utiliser des fractions, il y a de nombreux réels qui ne peuvent pas être représentés ainsi).

  14. #14
    screetch
    Invité(e)
    Par défaut
    mais si on a une fraction au départ et on ne fait que des additions, soustractions, multiplications et divisions, le résultat reste une franction.

  15. #15
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 965
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 965
    Par défaut
    Jai,

    Évidemment, mais tu ne pourras pas représenter tous les réels, il y a donc des restrictions.

  16. #16
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    En général, à l'origine de ce genre de problème il y a l'absence de réflexion sur la quantité manipulée et encore moins d'analyse numérique liée à l'impact des représentations et des incertitudes liées sur les algos utilisés.

  17. #17
    Membre confirmé
    Profil pro
    Étudiant
    Inscrit en
    Mai 2007
    Messages
    123
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2007
    Messages : 123
    Par défaut
    Je ne savais simplement pas que la représentation des nombres flottants n'était pas parfaite et je suis certain de mon algorithme.

  18. #18
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Personne ne doute que tu sois certain de ton algo.

    A mon avis il y a au- deux questions qui peuvent aider à décider du type de représentation utilisée pour la grandeur :

    => Est-ce que cela a un sens de manipuler des float/double plutôt que des int ? Par exemple, pour un compteur kilométrique d'un tableau de bord électronique d'une voiture, le cumul des km parcours aura probablement une précision à la centaine de mètre, au pire au mètre près. Certainement pas au cm ou au mm, nanomètre - en fait on peut faire le choix de réduire la précision à un ordre de grandeur donné. Donc l'utilisation d'un entier exprimant une distance en mètre peut être suffisant (un entier sur 32 bits va jusqu'à plus de 4 milliards, une voiture parcours rarement plus de 4 milliards de mètres ). Même si le déplacement de la voiture est continu et que mathématiquement, une distance est un réelle, cela n'a pas de sens.

    => Seconde question, quels traitements vas-tu faire et quels sont leurs interactions avec la représentation ? Si je reprends mon compteur kilométrique, j'ai une fonction simple cumul qui accumule les distances parcourues. Rien de plus simple, à chaque top, le nouveau cumul est le précédent incrémenté de la nouvelle mesure de mon capteur : cumul <- Prev Cumul + Delta.
    Sauf que
    1/ Si je prend des float/double, dès que cumul va être très grand et delta très petit, alors l'addition ne prend pas en compte delta
    2/ à l'inverse, si je prend des entiers, je dois probablement gérer une saturation de la quantité selon la précision que je garde dans cumul.
    Le type de représentation choisi et l'objectif de la données ont un impact sur la façon de coder l'algo même si on est sur de lui
    (et là, je ne pose même pas la question de savoir quelle est l'incertitude de la mesure compte tenu de l'incertitude du capteur et du nombre de cumul).

  19. #19
    Membre averti
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 23
    Par défaut Petite précision ;-)
    Bonjour,

    Je déterre ce vieux sujet pour un complément d'information :

    Dans une base access avec des données exportées depuis une base oracle quand je fait -4.2/0.12 le résultat est -35.0000007685 quelquechose comme ça en regardant le format de mes données, c'est du réel double (8octets).
    J'ai tout converti en réel simple (4 octets) et j'obtien bien -35.

    Trop de précision tue la précision...

    En éspérant que cela puisse aider des personnes confrontés au même problème que moi.
    ++

  20. #20
    Membre émérite
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Par défaut
    Citation Envoyé par tisstt Voir le message
    Dans une base access avec des données exportées depuis une base oracle quand je fait -4.2/0.12 le résultat est -35.0000007685 quelquechose comme ça en regardant le format de mes données, c'est du réel double (8octets).
    J'ai tout converti en réel simple (4 octets) et j'obtien bien -35.
    Effet d'affichage sûrement...

Discussions similaires

  1. float ou double, mauvais format?
    Par didier17062006 dans le forum C++Builder
    Réponses: 6
    Dernier message: 18/10/2006, 12h42
  2. [débutant] Convesion Float to double
    Par cyrill.gremaud dans le forum Langage
    Réponses: 7
    Dernier message: 12/07/2006, 09h06
  3. Problème conversion float vers double
    Par jhenaff dans le forum SQL Procédural
    Réponses: 3
    Dernier message: 27/01/2006, 10h39
  4. Conversion d'un tableau de float en double ?
    Par alex6891 dans le forum C++
    Réponses: 5
    Dernier message: 05/01/2006, 06h04
  5. float ou double ?
    Par Neilos dans le forum C++Builder
    Réponses: 4
    Dernier message: 16/01/2004, 20h12

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