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 :

Partie décimale d'un float


Sujet :

C

  1. #1
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut Partie décimale d'un float
    Bonjour à tous!
    Voila, pour un de mes codes j'ai besoin de récupérer la partie décimale d'un float et sans utiliser floor() (pour faire une soustraction ensuite) parce que je n'ai pas droit à la librairie math.h.
    J'utilise donc un cast. J'ai un truc du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    float f=2.76578;
     
    f-=(int)f;
    printf("%d",f);
    Seulement, pour certaines valeures, les résultats sont différents: par exemple 2.876, au lieu que j'obtienne 0,876, j'ai 0.875999...
    Je voudrais savoir pourquoi j'ai ce genre de résultat et savoir s'il y a un autre moyen de récupérer la prtie décimale.

  2. #2
    Membre habitué
    Homme Profil pro
    Inscrit en
    Juillet 2010
    Messages
    107
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 107
    Points : 189
    Points
    189
    Par défaut
    Slt,

    Pour la raison de ton problème de précision :
    http://en.wikipedia.org/wiki/Floatin...uracy_problems
    http://fr.wikipedia.org/wiki/Virgule_flottante

    Personnellement j'évite le plus souvent l'utilisation des nombres à virgule flottante, surtout sur les systèmes embarqués.
    Je préfère les entiers et adapter l'unité de mes variables.

    Sinon, si tu souhaites seulement faire un printf, il faut lui préciser le format de sortie.
    Un petit "man printf" dans google te donne :
    http://www.linux-kheops.com/doc/man/...sprintf.3.html

    Dans ton cas c'est :
    printf( "%'.2f", ta_variable_float );

    @+

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Citation Envoyé par dré kam Voir le message
    Seulement, pour certaines valeures, les résultats sont différents: par exemple 2.876, au lieu que j'obtienne 0,876, j'ai 0.875999...
    Je voudrais savoir pourquoi j'ai ce genre de résultat et savoir s'il y a un autre moyen de récupérer la prtie décimale.
    C'est dû au fait que 2,876 n'est pas un nombre fini en binaire.

    What every computer scientist should know about floating point arithmetic ;
    http://www.developpez.net/forums/d10...obleme-malloc/

    Dans le cas de 2,876, le nombre est arrondi par défaut ou par excès en atteignant la fin de la mantisse, et est arrondi par défaut à six chiffres après la virgule lorsque tu l'affiches en décimal.

    Ici, quand tu soustrais la partie entière, tu gagnes exactement deux bits, et tu te retrouves avec deux bits à zéro insérés au bout de la mantisse. Dans le calcul, ça suffit à faire arrondir le nombre par défaut plutôt que par excès.

    Le moyen le plus simple si tu ne veux pas utiliser de fonctions dédiés, dans ce cas, consiste à faire passer les décimales dans la partie entière, dans à multiplier par 1000 si tu veux garder trois décimales. Tu convertis le tout en entier, tu soustrais l'ex-partie entière elle-aussi multipliée par 1000, tu reconvertis en flottant et tu redivises par 1000.

  4. #4
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Je ne veux pas juste les afficher mais connaitre la partie décimale. Autrement dit, je voudrais avoir par exemple 0.65 pour 2.65 et non 2.649999.

  5. #5
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    C'est dû au fait que 2,876 n'est pas un nombre fini en binaire.

    Le moyen le plus simple si tu ne veux pas utiliser de fonctions dédiés, dans ce cas, consiste à faire passer les décimales dans la partie entière, dans à multiplier par 1000 si tu veux garder trois décimales. Tu convertis le tout en entier, tu soustrais l'ex-partie entière elle-aussi multipliée par 1000, tu reconvertis en flottant et tu redivises par 1000.
    Oui je comprends, ca marche. Mais je veux que ca marche avec n'importe quel float. Donc à combien de chiffres après la virgule s'arrète un float généralement? c'est-a-dire un %f avec printf.

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Citation Envoyé par dré kam Voir le message
    Donc à combien de chiffres après la virgule s'arrète un float généralement? c'est-a-dire un %f avec printf.
    C'est écrit dans mon précédent commentaire.

  7. #7
    Membre habitué
    Homme Profil pro
    Inscrit en
    Juillet 2010
    Messages
    107
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 107
    Points : 189
    Points
    189
    Par défaut
    La solution du coefficient multiplicateur fonctionne avec n'importe quel float. Tu dois juste définir dès le départ la précision que tu souhaites garder.

    Sinon, une autre méthode consiste à garder ta variable décomposée en numérateur et dénominateur.
    Du coup, les opérations mathématiques sur des entiers peuvent être réalisées sans aucune approximation et c'est seulement au moment de l'affichage que tu divises le numérateur par le dénominateur.

    Une multiplication par un nombre devient la multiplication du numérateur par ce nombre.
    Une division par un nombre devient la multiplication du dénominateur par ce nombre.
    Une addition par un nombre devient l'addition au numérateur du nombre multiplié par le dénominateur.
    Une soustraction par un nombre devient la soustraction au numérateur du nombre multiplié par le dénominateur.
    Après chaque opération est fortement conseillé de réaliser une simplification des fractions.

    Cette méthode permet la comparaison correct entre deux variables.

    Cette complexité est le prix de la précision. Mais as-tu vraiment besoin d'une telle précision ?

  8. #8
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    En fait je veux juste pouvoir afficher un float, passé en paramètre, à l'écran un peu comme printf.
    Ce matin j'ai encore essayé d'autres méthodes mais is se trouve que dés que je fais la moindre multiplication, la valeur est perdue (2.876*10=28.7599...).
    Est ce qu'il est possible de travailler directement avec la mentisse et l'exposant?

  9. #9
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    En fait je veux juste pouvoir afficher un float, passé en paramètre, à l'écran un peu comme printf.
    C'est-à-dire ?

    Ce matin j'ai encore essayé d'autres méthodes mais is se trouve que dés que je fais la moindre multiplication, la valeur est perdue (2.876*10=28.7599...).
    Détrompe-toi. La valeur est perdue dès le départ. C'est ce qui t'a été expliqué.
    Il ne faut pas confondre la précision de l'affichage avec printf et la précision de l'encodage d'un nombre à virgule flottante.

    Voilà ce que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    float valeur = 2.876;
    printf("%20.30f\n" , valeur);
    donne sur ma machine :
    2.875999927520752000000000000000
    Et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    double valeur = 2.876;
    printf("%20.30lf\n" , valeur);
    donne :
    2.875999999999999900000000000000
    C'est mieux, mais c'est pas encore ça.

    Tout ceci est directement lié au problème de précision de l'encodage des nombres à virgule flottante. Le µprocesseur de Mr et Mme Toutlemonde utilise la norme IEEE754 pour l'encodage des nombres à virgule flottante, codés sur 32 et 64 bits : http://en.wikipedia.org/wiki/IEEE_754-1985
    Même si tu travailles directement sur la mantisse, ça n'y changera rien puisque tu te heurtera au même problème. C'est propre à l'électronique.
    De plus, quelle que soit la taille de la mantisse, elle ne sera jamais infinie, et par conséquent tu obtiendras souvent des problèmes de précision du même genre.

  10. #10
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Alors comment je fais pour afficher 2,876 si on m'envoie cette valeur en paramètre sans utiliser printf (avec des write)?
    A la limite je veux bien afficher 2.87600 (avec un nombre de chiffres après la virgule que je définis a l'avance et valable quelque soit la valeur reçue.)

  11. #11
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Ben il faut arrondir, mais comme le nombre de départ est faussé, ça ne t'affichera pas quelque chose de précis par conséquent.
    Comme je t'ai expliqué, la valeur passée (en float) ne sera pas 2.876 mais quelque chose comme 2.875999927520752.

    Donc si tu veux par exemple afficher 6 chiffres après la virgule, tu peux utiliser printf comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("%.6f" , tavaleur);
    Mais là, ce n'est que la précision de l'affichage. Ca ne règle pas le problème de précision du nombre en lui-même.

  12. #12
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par jeroman Voir le message
    Donc si tu veux par exemple afficher 6 chiffres après la virgule, tu peux utiliser printf comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("%.6f" , tavaleur);
    Mais là, ce n'est que la précision de l'affichage. Ca ne règle pas le problème de précision du nombre en lui-même.
    Mais je ne dois pas utliser printf. Il me faut donc des write. Donc comment savoir quand arrondir dans le code? càd arrondir le 87599 en 876

  13. #13
    Membre chevronné
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Points : 1 750
    Points
    1 750
    Par défaut
    Le mieux c'est que tu donnes l'intitulé exact de ton exo, car là on part un peu dans toutes les directions, sans savoir ce que tu dois réellement faire. Surtout depuis ton histoire de write (qui, à première vue, n'a pas gros rapport avec l'histoire (?)), j'avoue que... je ne pige plus rien à ton problème.

  14. #14
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par jeroman Voir le message
    Le mieux c'est que tu donnes l'intitulé exact de ton exo, car là on part un peu dans toutes les directions, sans savoir ce que tu dois réellement faire. Surtout depuis ton histoire de write (qui, à première vue, n'a pas gros rapport avec l'histoire (?)), j'avoue que... je ne pige plus rien à ton problème.
    C'est tout simple: je dois recoder printf.

  15. #15
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Citation Envoyé par dré kam Voir le message
    C'est tout simple: je dois recoder printf.
    Et tu ne pouvais pas commencer par là ?

    Bon, comme on te le dit, c'est printf() qui fait la gestion de la précision des nombres à virgule flottante. Cette fonction ne s'appuie pas sur des fonctions d'affichage sous-jacentes qui feraient plus ou moins le même travail. Si tu dois réécrire printf(), tu dois apprendre comment on convertit des nombres binaires (à virgule) vers le décimal ou n'importe quelle autre base.

    Lis cette discussion : http://www.developpez.net/forums/d10...e/#post6052599

    L'idée générale est que tu vas afficher autant de décimales que tu le souhaites et, une fois cela fait, tu examines la décimale suivante. Tu fais ensuite un arrondi par défaut ou par excès selon que cette décimale soit comprise entre 0 et 4 ou entre 5 et 9.

    Lorsque tu arrondis par excès, il faut incrémenter la dernière décimale, et la propager tant que cette décimale et les suivantes sont des 9.

  16. #16
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Et tu ne pouvais pas commencer par là ?
    Lis cette discussion : http://www.developpez.net/forums/d10...e/#post6052599

    L'idée générale est que tu vas afficher autant de décimales que tu le souhaites et, une fois cela fait, tu examines la décimale suivante. Tu fais ensuite un arrondi par défaut ou par excès selon que cette décimale soit comprise entre 0 et 4 ou entre 5 et 9.

    Lorsque tu arrondis par excès, il faut incrémenter la dernière décimale, et la propager tant que cette décimale et les suivantes sont des 9.
    J'ai pris le temps de lire mais je ne comprends pas grand chose. Cependant j'ai fait un cours d'architecture et quelques recherches sur le stockage des nombres à virgule flottante (mantisse, exposant). Comment utiliser tout ça alors?

  17. #17
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Il faut apprendre à convertir un nombre vers la base de ton choix.

    Si tu veux afficher un nombre entier en base 10, par exemple, tu procèdes chiffre par chiffre. Tu fais une boucle qui fait passer chaque chiffre « de l'autre côté de la virgule » en divisant le nombre par 10, et en examinant à chaque fois le reste de cette division. Tu obtiens tous les chiffres de la représentation du nombre en base dix, mais dans le sens inverse. À toi de les remettre dans l'ordre (en utilisant une pile, par exemple).

    Lorsque que tu n'as que des chiffres après la virgule (donc « 0,xxxx »), tu procèdes de la même façon : tu multiplies par 10 pour faire, à chaque fois, passer un chiffre de l'autre côté de la virgule. Tu récupères à chaque tour la partie entière, et tu obtiens tous les chiffres, dans le bon ordre cette fois.

    Donc, quand tu as un nombre à virgule flottante quelconque à traiter, tu commences par sa partie entière, et tu poursuis par sa partie rationnelle.

  18. #18
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Il faut apprendre à convertir un nombre vers la base de ton choix.

    Si tu veux afficher un nombre entier en base 10, par exemple, tu procèdes chiffre par chiffre. Tu fais une boucle qui fait passer chaque chiffre « de l'autre côté de la virgule » en divisant le nombre par 10, et en examinant à chaque fois le reste de cette division. Tu obtiens tous les chiffres de la représentation du nombre en base dix, mais dans le sens inverse. À toi de les remettre dans l'ordre (en utilisant une pile, par exemple).

    Lorsque que tu n'as que des chiffres après la virgule (donc « 0,xxxx »), tu procèdes de la même façon : tu multiplies par 10 pour faire, à chaque fois, passer un chiffre de l'autre côté de la virgule. Tu récupères à chaque tour la partie entière, et tu obtiens tous les chiffres, dans le bon ordre cette fois.

    Donc, quand tu as un nombre à virgule flottante quelconque à traiter, tu commences par sa partie entière, et tu poursuis par sa partie rationnelle.
    Je ne saisis pas très bien. Tu fais allusion à la mantisse? J'ai fait ce code mais je n'arrive pas à le terminer.

    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
     
    void	my_putfloat(float nbr)
    {
      int	exp,e=0,manti;
      unsigned int	n=nbr;
    	char c;
     
    	c= n >>31;
    	if(c==1) //Le signe au 1er bit
    		printf("-"); 
    	exp=(((n)&(0x7FFFFFFF))>>23)-127; //L'exposant dans les 8 bits suivants
    	while(exp!=1)
    	{
    		exp/=2;
    		e++;
    	}
            printf("exposant=%d\n",e);
    	manti=(n)&(0x007FFFFF); //Je récupère la mantisse
    }
    Comment afficher les valeurs maintenant?

  19. #19
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Tu n'as pas besoin de manipuler directement les bits pour faire une conversion de base. C'est un problème purement algébrique. Je te donne un petit exemple, volontairement partiel, dont tu peux t'inspirer :

    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
    #include <stdio.h>
     
    int main (void)
    {
        int i = 43857;
     
        do
        {
            putchar ('0'+(i % 10));
            i /= 10;
        }
        while (i);
        puts ("");
     
        return 0;
    }
    Qu'obtiens-tu ?

  20. #20
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Janvier 2011
    Messages : 247
    Points : 163
    Points
    163
    Par défaut
    Oui mais si les nombres sont en binaires (comme dans la mantisse) et qu'on veut les afficher en décimal?

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. retourner la partie décimale d'un float
    Par sheridan08 dans le forum Général Python
    Réponses: 16
    Dernier message: 09/01/2022, 22h00
  2. Extraire la partie décimale d'un float
    Par kryptong dans le forum Débuter
    Réponses: 15
    Dernier message: 19/01/2013, 22h01
  3. Extraire la partie décimal d'un float en c
    Par souhe_nits dans le forum Débuter
    Réponses: 5
    Dernier message: 22/03/2011, 17h15
  4. Parties entière et décimale d'un float
    Par amateurc dans le forum Ada
    Réponses: 15
    Dernier message: 31/07/2008, 20h42
  5. Réponses: 15
    Dernier message: 30/01/2008, 18h23

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