2016-10-23 1 views
-2

J'essaie de comprendre ce code pendant environ une heure et toujours pas de chance.Luttant avec la sortie de l'union

#include <stdio.h> 
#include <stdlib.h> 

int f(float f) 
{ 
    union un {float f; int i;} u = {f}; 

    return (u.i&0x7F800000) >> 23; 
} 

int main() 
{ 
    printf("%d\n", f(1)); 

return 0; 
} 

Je ne comprends pas comment ce travail, je l'ai essayé f (1), f (2), f (3), f (4) et bien sûr obtenir les différents résultats. J'ai aussi beaucoup lu sur les syndicats et d'autres choses. Ce que j'ai remarqué que lorsque je supprime 0x7F800000 de retour, les résultats seront les mêmes. Je veux savoir comment u.i est généré, évidemment ce n'est pas une poubelle aléatoire mais aussi ce n'est pas un (1) de l'argument de la fonction. Qu'est-ce qui se passe ici, comment ça marche?

Répondre

2

Cela revient à comprendre comment les nombres à virgule flottante sont représentés en mémoire. (voir IEEE 754).

En bref, un nombre à virgule flottante de 32 bits aura la structure suivante

  • de bit 31 sera le bit de signe pour le nombre total
  • les bits 30-23 aura exposant du nombre, polarisé 127
  • Les bits 22-0 représentent la partie fractionnaire du nombre. Ceci est normalisé de sorte que le chiffre avant le point décimal (en fait binaire) est un.

En ce qui concerne l'union, rappelons que l'union est un bloc de mémoire de l'ordinateur qui peut contenir l'un des types à au moment, donc la déclaration:

union un 
    { 
     float f; 
     int i; 
    }; 

est la création d'un 32 bits bloc de mémoire pouvant contenir un nombre à virgule flottante ou un nombre entier, à un moment donné. Maintenant, quand nous appelons la fonction avec un paramètre à virgule flottante, le modèle binaire de ce nombre est écrit dans l'emplacement mémoire de un. Maintenant, lorsque nous accédons à l'union à l'aide du membre i, le modèle de bits est traité comme un entier.

Ainsi, la disposition générale d'un nombre à virgule flottante de 32 bits est seee eeee efff ffff ffff ffff ffff ffff, whese s représente le bit de signe, e les bits d'exposant et f les bits de fraction. OK, genre de charabia, j'espère qu'un exemple pourrait aider.

Pour convertir 4 en virgule flottante IEEE, convertissez d'abord 7 en binaire (j'ai divisé le nombre de 32 bits en quartets de 4 bits);

4 = 0000 0000 0000 0000 0000 0000 0000 0111 

Maintenant, nous devons normaliser cela, à savoir exprimer un nombre élevé à la puissance de deux;

1.11 x 2^2 

Ici, nous devons nous rappeler que chaque puissance de deux déplacer le point binaire à droite sur la place (analogue à traiter des puissances de 10).

De là, nous pouvons maintenant générer le modèle binaire

  1. le signe global du nombre est positif, de sorte que le bit global de signe est 0.

  2. l'exposant est 2, mais nous biaiser l'exposant avec 127. Cela signifie qu'un exposant de -127 serait stocké un 0, tandis qu'un exposant de 127 serait stocké comme 255. Ainsi, notre champ d'exposant serait 129 ou 1000 0001.

  3. Enfin, notre nombre normalisé serait 1100 0000 0000 0000 0000 000 000. Notez que nous avons laissé tomber le premier '1' parce qu'il a toujours supposé être là.

  4. Mettre tout cela ensemble, nous avons comme modèle binaire:

    4 = 0100 0000 1110 0000 0000 0000 0000 0000

Maintenant, le dernier petit est ici le sage bit et avec 0x7F800000 qui si nous écrivent en binaire est 0111 1111 1000 0000 0000 0000 0000 0000, Si nous comparons cela à la disposition générale d'un nombre à virgule flottante IEEE, nous voyons que ce que nous sélectionnons avec le masque est les bits de l'exposant, puis nous passons le à gauche 23 bits.

Votre programme imprime simplement l'exposant biaisé d'un nombre à virgule flottante. A titre d'exemple,

#include <stdio.h> 
    #include <stdlib.h> 

    int f(float f) 
    { 
     union un {float f; int i;} u = {f}; 

     return (u.i&0x7F800000) >> 23; 
    } 

    int main() 
    { 
     printf("%d\n", f(7)); 
     return 0; 
    } 

donne une sortie de 129 comme on peut s'y attendre.