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

  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 150
    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 150
    Billets dans le blog
    150
    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.

  7. #7
    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
    Donc si j'ai bien compris, dans le cas où l'on me demande de privilégier l'optimisation, je garde la solution du type fixe sur 32 bits car les calculs sont plus simples et moins de bits sont manipulés.

    Dans le cas où l'on me demande un programme qui manipule de grands nombres par exemple, il faut que j'envisage de changer le type fixe en une solution comme a cité LittleWhite, en utilisant une structure.

    Après je pense que si on me demande de coder un gameplay, la précision n'est pas si importante dans un jeu (dans la majorité des cas), donc par exemple un typedef int avec une norme de (1<<4), me permettrait de manipuler de plus grands nombres en sacrifiant un peu de précision (dîtes-moi si j'ai rien compris )

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


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 150
    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 150
    Billets dans le blog
    150
    Par défaut
    Simplement, si c'est le test que j'ai eu (soyons fous), il faut faire rebondir une balle sur l'écran.
    L'histoire est que la DS (comme quelques autres machines embarqués), non pas d'instructions pour calculer les virgules flottantes (ou lorsque cela est possible, c'est ultra lent).

    Du coup, en fait, c'est si on doit appliquer une vitesse qui décroit progressivement, à une balle, juste en utilisant les int, la vitesse minimale sera le pixel (ce qui ne donne pas un super effet). Du coup, on feinte le tout avec la structure que j'ai expliqué (ou similaire si vous voulez faire de l'optimisation mémoire).

    Ainsi, on augmente d'un, que lorsque la partie fractionnaire complète les 256 / 256
    Pour la précision (32bits) pour l'int, on s'en fout un peu, dans le sens il est très rare de devoir représenter des grands nombres (rappel, je parlais des coordonnées en pixel d'une balle, soit ... toujours < 500 sur la DS (ou presque)).

    La solution que je donne, c'est celle que l'on m'a donné pendant l'entretien (même si nous ne sommes pas rentré dans les détails).
    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.

  9. #9
    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
    Je veux le même test *_* Tout de manière je pense que si ce n'est pas ça, se sera quelque chose de similaire genre une petite démo de jeu de plateforme avec un peu de physique (j'aurai 2heures pour le réaliser).

    Pour ce qui est de l'int au lieu de la structure, on résonne donc par fractions de 256 (soit 8 bits), pourquoi serait-on limiter à une vitesse minimum de 1pixel ?

    Si on utilise par exemple comme vitesse 64 (en valeur fixe), cela fait du 64/256 soit du 0.25 en vitesse non ?

    Comme ça on peut réguler la vitesse même en dessous de 256 (1pixel/frame), on ajoutera juste 64 à notre valeur de position.

    Peut-être je me trompe, je dis pas que j'ai pas faux, mais je voyais ça comme ça.
    En tout cas merci de me faire partager ton experience de l'entretien =)

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


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    27 150
    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 150
    Billets dans le blog
    150
    Par défaut
    On est limité lorsque l'on utilise ne met pas en place un système pour simuler les nombres à virgules. Je veux dire par là que si on a une vitesse, qui est un nombre entier, alors , il ne sera pas possible d'aller moins vite que 1 (sauf 0, mais nous parlons d'un déplacement, pas d'un arrêt). C'est pour cela que l'on met en place ce système pour simuler les nombres à virgules.
    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.

+ 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