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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  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
    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é)

  5. #5
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    615
    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 : 615
    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

  6. #6
    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

  7. #7
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    615
    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 : 615
    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.

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