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 :

Manipulation de bits


Sujet :

C

  1. #1
    Membre du Club
    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Novembre 2007
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Directeur des systèmes d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2007
    Messages : 53
    Points : 52
    Points
    52
    Par défaut Manipulation de bits
    Bonjour,

    Je vous expose mon problème; je dispose de données stockées en binaire complément à 2 sur 17 bits avec le MSB à gauche. La donnée est stockée en mémoire sur 3 octets (Considérant que l'indice 0 est le MSB et qu'il est à gauche, les bits de 17 à 24 sont donc inutilisés).

    La donnée représente un roulis de navire, le MSB utile représente 45°.
    le bit suivant 22.5° ...

    Je souhaite récupérer cette valeur sous une forme dirons nous plus "standard" : décimale.

    Mon programme est en c++ et je développe sous Borland C++.

    Quelle est la méthode la plus astucieuse pour réaliser cette convertion ?

    Merci beaucoup pour votre aide.

  2. #2
    Invité(e)
    Invité(e)
    Par défaut
    Bonsoir,

    Citation Envoyé par athomas Voir le message
    je dispose de données stockées en binaire complément à 2 sur 17 bits avec le MSB à gauche.
    La donnée représente un roulis de navire, le MSB utile représente 45°.
    le bit suivant 22.5° ...
    On est d'accord, +45° sera codé 0 1000 0000 0000 0000, (le premier zéro étant le bit de signe) ?
    Peux tu donner un exemple ?

    Citation Envoyé par athomas Voir le message
    Quelle est la méthode la plus astucieuse pour réaliser cette conversion ?
    Vu la présence du complément à deux, j'aurai tendance à stocker les bits dans une structure capable de les accueillir (un singed long int) et d'appliquer une bête multiplication.

    C'est qu'on va faire, c'est donc utiliser un long int, en laissant les 15 derniers bits à 0.
    Pourquoi les 15 dernier et les les 15 premier ? à cause du complément à deux.

    La partie difficile du problème est de bien mettre les données de roulis dans l'entier : de placer les bits aux bons endroits.

    Une fois que cette étape sera effectuée, tu te retrouvera avec un type plus facile à manipuler.

    En pratique, ça donne ça :
    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
    int main(void) 
    {    
        /* données bord ... un exemple plize */
        char data[3] = ...;
        long long int conv = 0;
        /* bits utiles */
        long long int mask = 0xffff8000;
        long long int roulis_max = 0x7fff8000;
        double roulis;
     
        /* copie des données bors dans conv */
        ...
     
        /* limitation aux 17 premiers bits */
        conv &= mask;
     
        /* conversion du roulis en angle */
        roulis = (double)conv / (double roulis_max) * 45.;
     
     
        return 0;
    }
    Sinon, une fonction bien utile pour voir où sont tes bits dans tes entiers.
    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 display(long int number)
    {
        int i;
        unsigned long int bit = 0x80000000;
        unsigned long int tmp;
        memcpy(&tmp, &number, sizeof number);
     
        printf("%16d = 0x", number);
        for(i = 0; i < 32; ++i)
        {
            if(i%8 == 0){
                putchar(' '); 
            }
            putchar(tmp & bit ? '1' : '0');
            bit /= 2;
        }
        puts("");
     
    }
    Dernière modification par Invité(e) ; 07/01/2011 à 13h41.

  3. #3
    Membre du Club
    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Novembre 2007
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Directeur des systèmes d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2007
    Messages : 53
    Points : 52
    Points
    52
    Par défaut
    On est d'accord, +45° sera codé 0 1000 0000 0000 0000, (le premier zéro étant le bit de signe) ?
    Peux tu donner un exemple ?
    Je n'ai pas un exemple très intéressant à te donner ...

    Voici par contre un classeur de calcul excel que j'ai créé et qui permet de réaliser le calcul en question : (disponible jusqu'au 10/02/2011)
    http://dl.free.fr/pIPpW39AR



    Comment placer les données de base dans un entier ?

  4. #4
    Invité(e)
    Invité(e)
    Par défaut
    Citation Envoyé par athomas Voir le message
    Comment placer les données de base dans un entier ?
    C'est pour ça que je te demandais un exemple, ma boule de cristal n'est pas réparée.

    Pour copier un octet complet, utilise simplement = avec les casts qui vont bien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    /* données bord */
    unsigned char data[4];
     
    /* l'entier de stockage (cf exemple du post précédent)*/
    int conv;
     
    /* pointeur sur conv*/
    unsigned char * p = &conv;
     
    /* après, on utilise simplement : */
    p[x] = data[y];
    Si tu as un décalage entre le début des données bord et ton entier, utilise simplement (tu as vu, c'est toujours simple ;) l'opérateur <<= ou >>= selon le besoin.

  5. #5
    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 problème, c'est que cette solution n'est pas portable à cause de l'endianness et de la taille du "int" (qui ne fait pas toujours 4 octets).

    La solution à base de décalages de bits me semble plus appropriée.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    107
    Détails du profil
    Informations personnelles :
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2006
    Messages : 107
    Points : 124
    Points
    124
    Par défaut
    Bonsoir,

    Je n'ai pas bien compris, tu dis dans ton premier post que les bits de 17 à 24 sont inutilisés, mais dans ton testeur de trame tu leur donnes des valeurs...

    D'après ce que j'ai compris, tu as un nombre codé en complément à 2, MSB à gauche.
    Prenons par exemple : 10001000010000000000000000000000
    Le bit de gauche (MSB) est le bit de signe, ensuite viennent les 17 bits qui t'interessent.

    Si on enlève le complément à gauche, on a : 01110111110000000000000000000000.
    Lebit de gauche ets toujours le bit de signe. Ensuite, on a :
    1*45° + 1*22.5 + 1*11.25° + 0*5.625 + 1*2.8125 + 1* 1.40625 + ...

    C'est bien ça ?

    J'ai fait rapidement le code suivant qui implémente l'exemple donnée au dessus. Evidemment, il faudra modifier les accès aux bits si j'ai compris de travers, et il faudrait aussi le modifier pour que le code marche sur une architecture autre que 32 bits.

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
     
    #include <stdio.h>
    #include <stdlib.h>
     
    #define NB_BITS 17
    #define VAL_BIT(i_nb, i_indice_bit)  ((i_nb>>i_indice_bit)&1)
     
     
    /**récuperer dans une chaine de caractere la representation 
    binaire i_N-bits d'un nombre passé en param. 
    ch doit avoir au moins i_N+1 caracteres**/
    void int_to_bin(const int i_N, char *c_ch, const int i_nb){
    	int i,j=0;
    	for (i=i_N-1; i>=0; i--) c_ch[j++]= ( ((i_nb>>i)&1 )==0 ) ? '0' : '1' ;
    	c_ch[j]='\0';
    }
     
     
     
    int main (void) {
    	int i_cpt;
    	int i_acces;
    	char c_aff[33]; /* 32 bits + fin de chaine*/
     
    	float f_tab_conversion[NB_BITS];
    	float f_res=0;
     
    	/*init tableau de conversion*/
    	f_tab_conversion[0]=45.0;
    	for (i_cpt=1; i_cpt<NB_BITS; i_cpt++)
    		f_tab_conversion[i_cpt]=f_tab_conversion[i_cpt-1]/2.0;
     
    	/* i_conv est l'entier à convertir */
    	int i_conv= (1<<31)|(1<<27)|(1<<22);
     
    	/* affichage de la representation binaire */
    	int_to_bin(32, c_aff, i_conv);
    	printf("A convertir : %d = \"%s\"\n",i_conv, c_aff);
     
    	/* on enleve le complément à deux */
    	char c_inv=0;
    	/* complément à deux : on parcourt de droite à gauche. 
    	On garde le 1er bit à 1 inchangé, et on inverse tous les bits qui suivent */
    	for (i_cpt=0; i_cpt<32; i_cpt++)
    	{
    		if ( c_inv==0 && VAL_BIT(i_conv,i_cpt)==1 )
    		{
    			c_inv=1;
    			continue;
    		}
    		if (c_inv == 1)
    		{
    			if ( VAL_BIT(i_conv,i_cpt)==1 )
    				/* forcage du bit i_cpt à 0 */
    				i_conv &= ~(1<<i_cpt);
    			else
    				/* forcage du bit i_cpt à 1 */
    				i_conv |= (1<<i_cpt);
    		}
    	}
     
    	/* affichage de la representation binaire */
    	int_to_bin(32, c_aff, i_conv);
    	printf("Apres avoir enlever complement a deux : %d = \"%s\"\n",i_conv, c_aff);
     
    	/* On calcule la valeur : */
    	for (i_cpt=1; i_cpt<NB_BITS+1; i_cpt++)
    	{
    		i_acces = 32-i_cpt-1;
    		if ( VAL_BIT(i_conv,i_acces)==1 )
    		{
    			f_res += f_tab_conversion[i_cpt-1];
    		}
    	}
     
     
    	printf("Angle trouvé : %f\n",f_res );
     
    	return EXIT_SUCCESS;
    }

    Exemple d'execution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    A convertir : -2009071616 = "10001000010000000000000000000000"
    Apres avoir enlever complement a deux : 2009071616 = "01110111110000000000000000000000"
    Angle trouvé : 84.199219
    Bonne soirée

  7. #7
    Membre du Club
    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Novembre 2007
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Directeur des systèmes d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2007
    Messages : 53
    Points : 52
    Points
    52
    Par défaut
    Merci à vous pour vos réponses,

    J'essaye de me sortir de ce problème aujourd'hui et je reviens vers vous en cas de problème.

    En fait dans le simulateur excel; on remarque que les poids des bits "non utiles" valent 0, donc la valeur du bit n'a pas d'importance.


    Je remarque qu'il n'est quand même pas très simple de placer mon tableau de 3 octets qui représente ma valeur dans un conteneur vraiment utilisable sur toutes les architectures.

  8. #8
    Membre du Club
    Homme Profil pro
    Directeur des systèmes d'information
    Inscrit en
    Novembre 2007
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Directeur des systèmes d'information
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2007
    Messages : 53
    Points : 52
    Points
    52
    Par défaut
    Je reviens vers vous puisque j'ai maintenant une solution qui fonctionne


    quel que soit le nombre d'octets sur lesquels la valeur est stockée et quel que soit le nombre de bits utiles dans la trame.

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    /**
     * Fonction permettant de convertir une valeur contenue dans un tableau de
     * unsigned char. 
     * @param [in, out] array : tableau de unsigned char (données d'entrée)
     * @param [in] byte_cnt : nombre d'octets du tableau de données
     * @param [in] bits_cnt : nombre de bits utiles. Nécessairement < 8*byte_cnt.
     * @param [in] msb_val : valeur du bit de poids fort.
     * @param [in] isSigned : vaut true quand la valeur est codée en complément à 2,
     *                        false si c'est du binaire pur.
     * @return cette fonction renvoi la valeur décimale du nombre saisi en entrée.
     */
    double byteArrayToInt( 	unsigned char * array, size_t byte_cnt, size_t bits_cnt,
    						double msb_val, bool isSigned = false )
    {
    	double val = 0;
    	bool isNegative = false;
     
    	// on peut faire vérification de 8*bits_cnt < byte_cnt.
     
    	//1 : si on a un nombre signé, on regarde s'il est négatif ou non.
    	if (isSigned) {
    		// Est ce que le nombre est négatif (cad premier bit à 1) ?
    		isNegative = array[0] >> 7;
    	}
     
    	// decoder le complement à 2 si besoin .
    	if (isSigned && isNegative) {
    		// soustraire 1
    		// On met les bits inutiles à 0
    		unsigned int nbUselessBits = byte_cnt*8-bits_cnt;
    		// PREREQUIS: (byte_cnt-1)*8 < bits_cnt <= byte_cnt*8
    		array[byte_cnt-1] &= 0xFF << nbUselessBits;
    		// On soustrait 1
    		for (unsigned int i=byte_cnt; i>0; i--) {
    			unsigned char previousValue = array[i-1];
    			array[i-1]=array[i-1]-1;
    			if (array[i-1]<previousValue) {
    				// On n'a pas de retenue à propager au byte d'après
    				break;
    			}
    		}
     
    		// inverser les bits
    		for (unsigned int i=0; i<byte_cnt; i++) {
    			array[i] ^= 0xFF;
    		}
    	}
     
     
    	//2 : Calcul de la valeur de sortie
    	size_t cur_byte = -1 ;
    	for (size_t ibit = 0; ibit < bits_cnt; ibit++) {
    		if (ibit % 8 == 0) {
    			cur_byte++;
    		}
    		unsigned char state = 0;
    		state = 0x01 & (array[cur_byte] >> (7-((ibit-8*cur_byte))));
     
    		val += msb_val * state;
    		msb_val /= 2;
    	}
     
    	if (isSigned && isNegative) {
    		val *= -1 ;
    	}
     
    	return val;
    }

    Merci donc pour votre aide à tous.

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

Discussions similaires

  1. manipulation de bits d'un byte
    Par orelero dans le forum Langage
    Réponses: 6
    Dernier message: 22/08/2008, 10h41
  2. word_t et Manipulation de bits
    Par fmichael dans le forum C#
    Réponses: 2
    Dernier message: 19/03/2007, 09h33
  3. [VS 2005] Manipuler des bits
    Par b_lob dans le forum C#
    Réponses: 5
    Dernier message: 05/02/2007, 09h51
  4. [Ada] Manipulation de "Bits"
    Par BoBy9 dans le forum Ada
    Réponses: 2
    Dernier message: 14/06/2006, 11h57
  5. Manipulation de bits
    Par Tsly dans le forum C++
    Réponses: 2
    Dernier message: 28/09/2005, 12h41

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