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 :

Problème précision virgule fixe


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut Problème précision virgule fixe
    Bonsoir, ayant postulé pour un poste de programmeur gameplay, on m'a avertit que le test porterait sur un test de gameplay pour une DS, en C, avec des calculs à virgule fixe.

    En ce qui concerne le langage C aucun problème, mais ayant toujours développé sur pc, c'est les calculs à virgule fixe qui me posent un peu de soucis.

    Je me suis donc renseigné dessus (ayant reçu l'email hier), et j'en viens à vous voir pour essayer d'être à l'aise avec et enlever certains doutes.

    Je vous expose donc un code d'addition que j'ai fais pour essayer de comprendre :

    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
     
    int _tmain(int argc, _TCHAR* argv[])
    {
    	float fNb1 = 23.45;
    	float fNb2 = 45.32;
     
    	printf("AdditionInt : %d \n", AdditionInt(fNb1, fNb2));
    	printf("AdditionFloat : %f \n", AdditionFloat(fNb1, fNb2));
     
    	_getch();
    	return 0;
    }
     
    int AdditionInt(int _iNb1, int _iNb2) // reçoit 2 int (pour pouvoir faire un décalage binaire)
    {
    	int a = (_iNb1 << 8); // met en virgule fixe
    	int b = (_iNb2 << 8);
     
    	return (a+b) >> 8; // retourne le résultat en int
    }
     
    float AdditionFloat(float _fNb1, float _fNb2) // reçoit 2 float
    {
    	float a = (_fNb1*(float)(1<<8)); // met en virgule fixe
    	float b = (_fNb2*(float)(1<<8));
     
    	return ((a + b) / (float)(1<<8)); // retourne le resultat en float
    }
    (Bien entendu je retourne la valeur directement en int ou float, mais j'aurais pu retourner la valeur fixe pour effectuer d'autres calculs avant de convertir)

    Donc je me suis fixé un décalage binaire de 8 pour ma virgule fixe, et ce que je ne suis pas sûr c'est laquelle de ces deux fonctions d'additions (ou une autre que j'ai pas vu) serait la plus appropriée pour des calculs.

    Car la syntaxe que j'ai le plus vu, est celle de "AdditionInt", où on effectue un décalage binaire vers la gauche pour obtenir la valeur fixe, le problème c'est qu'après avoir effectué ce calcul avec les deux int, je me retrouve avec un résultat de 68 où toute précision est perdue.

    Donc en concidérant que je programme sur une DS et qu'il faille absolument optimiser etc... la fonction "AdditionFloat" est elle bonne ou ya il un moyen de retrouver la précision en modifiant un peu la fonction "AdditionInt" ?

    Je vous remercie d'avance de bien vouloir m'aider, et je suis ouvert à tout conseil et/ou correction.

    Lyofen

  2. #2
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    C'est forcé que tu n'aies aucune précision, tes float sont convertis en int AVANT d'être mis au format fixe. C'est comme si tu faisais 23+45.

    Pour fixer les idées, voila un bout de programme où les nombres sont convertis en virgule fixe, l'opération est faite, puis on affiche quel est le nombre représenté par le résultat en virgule fixe et la même opération directement entre float :
    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
    #include <stdio.h>
    typedef int Fixe;
    #define NORME (1<<8)
    //----------------------------------
    Fixe float2Fixe(float f)
    {
      return f*NORME;
    }
    //----------------------------------
    float fixe2Float(Fixe f)
    {
      return f/(float)NORME;
    }
    //----------------------------------
    Fixe AddFixe(Fixe f1, Fixe f2)
    {
       return f1+f2;
    }
    //----------------------------------
    Fixe MultFixe(Fixe f1, Fixe f2)
    {
      return f1*f2/NORME;
    }
    //----------------------------------
    int main(void)
    {
       float fNb1 = 23.45;
       float fNb2 = 45.32;
       printf("AdditionFixe : %f \n", fixe2Float(AddFixe(float2Fixe(fNb1),float2Fixe(fNb2))));
       printf("AdditionFloat : %f \n", fNb1+fNb2);
       printf("MultFixe : %f \n", fixe2Float(MultFixe(float2Fixe(fNb1),float2Fixe(fNb2))));
       printf("MultFloat : %f \n", fNb1*fNb2);
       return 0;
    }
    AdditionFixe : 68.765625
    AdditionFloat : 68.770000
    MultFixe : 1062.632812
    MultFloat : 1062.754027

  3. #3
    Membre averti
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Oui voilà, donc en gros c'est la même méthode que celle de ma fonction "AdditionFloat".

    Ce qui me gênait c'était cette histoire de norme, mais en gros on se fixe un nombre de bits de décalage, par exemple 8, et on est forcé d'utiliser des méthodes différentes pour mettre en valeur fixe (val<<8 pour les int, et val*(float)(1<<8) pour les float), il n'y a pas de méthode pour transformer tout d'un coup en valeur fixe.

    Ca paraissait logique à première vue mais n'ayant jamais vu ça jusque hier, je voulais être sûr de la méthode à utiliser et ne pas partir sur une fausse route.

    Je me permettrai de reposter une réponse si jamais je rencontre un nouveau problème sur ces virgules fixe afin d'éviter d"ouvrir un sujet à chaque fois, dans le cas contraire je mettrai résolu.

    En tout cas merci beaucoup !

  4. #4
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 27 070
    Billets dans le blog
    143
    Par défaut
    Bonjour,

    J'ai eu cette question plus ou moins récemment (peut être dans la même boite que vous ).
    La solution sera d'utiliser une structure, qui contient un int et un unsigned char. Le int est votre valeur et le unsigned char est en fait la valeur de ce qu'il y a après la virgule. Plus précisément, cela représentera le 1/256. Et grâce à un décalage de bit, la division est facilement applicable (pour un faible coût) (j'ai un peu de mal à l'expliquer )
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  5. #5
    Membre averti
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Bonjour,

    Merci beaucoup pour cette précision, jusque là j'ai utilisé la méthode de diogene en mettant toutes les valeurs fixe en type "Fixe", en transformant les types entiers avec val<<8 et les types décimaux avec val*(1<<8), ensuite j'effectue tous les calculs necessaire et je retransforme dans le type voulu après.

    J'utilise une division avec ce type "Fixe" donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Fixe DivisionFixe( Fixe _f1, Fixe _f2 )
    {
    	return ((_f1 << 8) / _f2 );
    }
    Je refais un décalage sur le dividende, et avec cette opération ça marche plutôt bien.

    Après je n'ai pas testé la méthode de la structure avec un unsigned char pour la partie décimale, si durant votre entretien vous avez eu des retours sur les meilleures méthodes à utiliser, je serais ravi de pouvoir en discuter (peut-être en mp =°).

    Merci !

  6. #6
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Si je comprend LittleWhite, cela consiste à coder les fixes sur un int+char, avec le point binaire à la droite du int (32 bits pour la partie entière, 8 bits pour la partie fractionnaire par exemple)
    Ce que tu proposes est de coder sur un int avec le point binaire à la droite du bit N°7 (24 bits pour la partie entière, 8 bits pour la partie fractionnaire dans l'exemple)
    La précision absolue est la même dans les deux cas, seule l'étendue des nombres représentables diffère.
    Par contre, les opérations se compliquent singulièrement et les performances calculatoires vont chuter.

    Donc, le choix dépend des contraintes du problème.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 08/03/2006, 16h57
  2. Problème de virgule
    Par Drax dans le forum Débuter
    Réponses: 12
    Dernier message: 04/12/2005, 14h40
  3. [D7] Problème de virgule flottante
    Par Magnus dans le forum Langage
    Réponses: 17
    Dernier message: 22/09/2005, 14h56
  4. [Kylix] Problème de virgule/DBExpress
    Par jeanphy dans le forum EDI
    Réponses: 5
    Dernier message: 12/02/2003, 16h29
  5. Chiffre a Virgule Fixe
    Par garybaldi dans le forum C
    Réponses: 3
    Dernier message: 21/06/2002, 10h41

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