Nous savons que l'entier est stocké en mémoire sous la forme de son complément à deux, alors comment la virgule flottante est-elle stockée en mémoire ?
Prenons un exemple de problème pour étudier ce problème :
#include <stdio.h>
int main()
{
int n = 9;
float* pFloat = (float*)&n;
printf("n的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
*pFloat = 9.0;
printf("n的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
return 0;
}
Vous pouvez essayer de faire cette question, quel est le résultat de sortie ?
résultat de l'opération :
Règles de stockage des nombres à virgule flottante
n et *pFloat sont évidemment le même nombre en mémoire, pourquoi y a-t-il un si grand écart de sortie ?
- (-1)^S * M * 2^E
- (-1)^S représente le bit de signe, lorsque S=0 , V est un nombre positif ; lorsque S=1 , V est un nombre négatif.
- M représente un nombre valide, supérieur ou égal à 1 et inférieur à 2 .
- 2^E signifie bits d'exposant.
Beaucoup de gens peuvent être confus quand ils voient cela, qu'est-ce que c'est ? En fait, c'est très simple, (-1)^S * M * 2^E peut être compris comme une formule, ^ signifie puissance, par exemple, 2^E est 2 à la puissance E, par exemple :
Decimal 5.0 , écrit en binaire est 101.0 , et la virgule décimale est avancée de deux places, ce qui équivaut à écrire selon la formule ci-dessus, vous pouvez obtenir :
, S=0, M=1.01, E=2.
IEEE 754 stipule :
Pour les nombres à virgule flottante de 64 bits, le bit le plus élevé est le bit de signe S , les 11 bits suivants sont l'exposant E et les 52 bits restants sont le chiffre significatif M.
IEEE 754 a des réglementations spéciales sur le chiffre significatif M et l'exposant E.
Comme mentionné précédemment, 1≤M<2, c'est-à-dire que M peut s'écrire sous la forme 1.xxxxxx, où xxxxxx représente la partie décimale.
IEEE 754 stipule que lorsque M est enregistré dans l'ordinateur, le premier chiffre de ce numéro est toujours 1 par défaut, il peut donc être ignoré, et seule la partie xxxxxx suivante est enregistrée. Par exemple, lors de l'enregistrement de 1.01, enregistrez uniquement 01, puis ajoutez le premier 1 lors de la lecture. Le but est d'économiser 1 chiffre significatif. En prenant le nombre à virgule flottante 32 bits comme exemple, il ne reste plus que 23 bits pour M. Une fois le premier 1 supprimé, cela équivaut à enregistrer 24 chiffres significatifs.
Quant à l'indice E, la situation est plus compliquée.
Premièrement, E est un entier non signé (unsigned int)
Cela signifie que si E est de 8 bits, sa plage de valeurs est de 0 à 255. Si E est de 11 bits, sa plage de valeurs est de 0 à 2047. Cependant, nous savons que E en notation scientifique peut apparaître des nombres négatifs, donc IEEE 754 stipule que lors du stockage de la valeur réelle de E dans la mémoire, un nombre intermédiaire doit être ajouté. Pour E 8 bits, le nombre intermédiaire est 127. Pour E 11 bits, le nombre intermédiaire est 1023. Par exemple, Le E de 2^ 10 est 10, donc lors de son enregistrement en tant que nombre à virgule flottante 32 bits, il doit être enregistré sous 10+127=137, soit 10001001.
Ensuite, l'indice E est extrait de la mémoire et peut être divisé en trois cas :
E n'est pas tout à 0 ou pas tout à 1
À ce moment, le nombre à virgule flottante est représenté par les règles suivantes, c'est-à-dire que la valeur calculée de l'exposant E est soustraite par 127 (ou 1023) pour obtenir la valeur réelle, puis le premier chiffre 1 est ajouté avant le nombre effectif M.
Par exemple:
La forme binaire de 0,5 est 0,1. Puisqu'il est stipulé que la partie positive doit être 1, c'est-à-dire que la virgule est décalée vers la droite de 1, alors c'est 1.0*2^(-1), et son code d'ordre est -1+127=126, qui est exprimé par 01111110, tandis que la mantisse 1.0 supprime la partie entière pour être 0, remplit 0 à 23 chiffres 000000000000000000000000, alors sa représentation binaire est :
0 01111110 00000000000000000000000
E est tout 0
A ce moment, l'exposant E du nombre à virgule flottante égal à 1-127 (ou 1-1023) est la valeur réelle, et le nombre effectif M n'est plus additionné du premier chiffre de 1, mais est restauré à un décimal de 0.xxxxxx. Ceci est fait pour représenter ± 0 et de très petits nombres proches de 0.
E est tout 1
A ce moment, si les chiffres significatifs M sont tous 0, cela signifie ± l'infini (positif ou négatif dépend du bit de signe S).
Voilà, c'est tout pour les règles de représentation des nombres à virgule flottante.
expliquer le sujet précédent
#include <stdio.h>
int main()
{
int n = 9;
float* pFloat = (float*)&n;
printf("n的值为:%d\n", n); //9
//n的值没有被改变,所以还是9
printf("*pFloat的值为:%f\n", *pFloat); //0.000000
//整型9在内存中的补码:00000000 00000000 00000000 00001001
//*pFloat是一个单精度浮点型,以浮点型的方式取出9:
//0 00000000 00000000000000000001001
//S=0, E=00000000, M=0000000000000000001001
//可见E为全0,按照前面讲的规则,E的真实值=1-127=-126,M的真实值=0.00000000000000000001001
//套用前面的公式:(-1)^0 * 0.00000000000000000001001 * 2^-126
//显然,这是一个非常小的数字,而打印时只能打印出小数点后6位,所以是0.000000
*pFloat = 9.0;
printf("n的值为:%d\n", n); //1091567616
//n的值通过*pFloat指针被重新赋为浮点型的9.0
//9.0直接转为二进制 -> 1001.0,按规则把小数点提前3位 -> 1.001 * 2^3,
//且9.0是正数,最终转换为:(-1)^0 * 1.001 * 2^3
//S=0, E=3+127=130, M=1.001
//那么,第一位的符号位S=0,指数E=3+127=130,写成二进制形式:10000010,有效数字M=001,后面补20个0凑满23位
//所以,写成二进制形式应该是S+E+M,即:
//0 10000010 00100000000000000000000000
//把这个二进制数字转换为十进制正是1091567616
printf("*pFloat的值为:%f\n", *pFloat); //9.000000
//浮点数以%f直接取出就是9.000000
return 0;
}