[Langage C avancé 3 - stockage de données (3) - stockage et récupération des nombres à virgule flottante en mémoire]


avant-propos

Cet article apprend ensuite le contenu lié au stockage des données, apprenant principalement le stockage et la récupération des nombres à virgule flottante en mémoire.


3. Stockage en virgule flottante en mémoire

  • Nombres à virgule flottante courants : 3,14159, 1E10
  • La famille des virgules flottantes comprend : les types float, double, long double
  • La plage de nombres à virgule flottante : définie dans float.h

3.1 Exemple de stockage de nombres à virgule flottante

int main()
{
    
    
	int n = 9;
	float *pFloat = (float*)&n;
	printf("n的值为:%d\n",n);
	printf("*pFloat的值为:%f\n",*pFloat);
	
	*pFloat = 9.0;
	printf("num的值为:%d\n",n);
	printf("*pFloat的值为:%f\n",*pFloat);
	return 0;
}

À première vue, la sortie est : 9, 9.0, 9, 9.0

Le résultat de l'exécution est illustré dans la figure suivante :
insérez la description de l'image ici

3.2 Règles de stockage en virgule flottante

num et *pFloat sont évidemment le même nombre en mémoire, mais les résultats d'interprétation des nombres à virgule flottante et des entiers seront très différents.Pour comprendre ce résultat, vous devez comprendre comment les nombres à virgule flottante sont représentés à l'intérieur de l'ordinateur.

Selon la norme internationale IEEE (Institute of Electrical and Electronics Engineering) 754, tout nombre binaire à virgule flottante V peut être représenté sous la forme suivante :

  • (-1)^S * M * 2^E
  • (-1)^s représente le bit de signe, quand s=0, V est positif ; quand s=1, V est négatif
  • M représente un nombre significatif, supérieur ou égal à 1, inférieur à 2
  • 2^E signifie bit d'exposant

par exemple:

  • 5.0 en décimal, écrit en binaire est 101.0, ce qui équivaut à 1.01×2^2
  • Selon les règles de stockage ci-dessus, nous pouvons obtenir s=0, M=1.01, E=2.
  • Décimal -5.0, écrit en binaire est -101.0, équivalent à -1.01×2^2
  • Selon les règles de stockage ci-dessus, s=1, M=1.01, E=2

3.3 Réglementations IEEE 754

  • Pour un nombre à virgule flottante de 32 bits, le 1 bit le plus élevé est le bit de signe s, les 8 bits suivants sont l'exposant E et les 23 bits restants sont le significande M
    insérez la description de l'image ici

  • Pour les nombres à virgule flottante 64 bits, le 1 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 significande M
    insérez la description de l'image ici

3.4 Dispositions particulières de l'IEEE 754 pour les chiffres significatifs M

  • Dans le règlement, 1≤M<2, c'est-à-dire que M peut s'écrire sous la forme 1.xxxxxx, où xxxxxx représente la partie fractionnaire
  • Lors de l'enregistrement de M 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, seul 01 est enregistré et lorsqu'il est lu, le premier 1 est ajouté. Le but est d'économiser 1 chiffre significatif
  • En prenant un nombre à virgule flottante de 32 bits comme exemple, il ne reste que 23 bits pour M. Après avoir arrondi le 1 du premier chiffre, cela équivaut à enregistrer 24 chiffres significatifs.

3.5 Dispositions spéciales pour l'exposant E dans IEEE 754

3.5.1 Le stockage en mémoire est une exigence de E

E est un entier non signé (unsigned int)

  • Si E est 8 bits, sa plage de valeurs est 0-255
  • Si E est 11 bits, sa plage de valeurs est 0~2047

Cependant, E en notation scientifique peut être négatif, donc IEEE 754 stipule que la valeur réelle de E doit être additionnée d'un nombre intermédiaire lorsqu'elle est stockée en mémoire :

  • Pour un E 8 bits, le nombre du milieu est 127
  • Pour un E à 11 chiffres, le nombre du milieu est 1023
  • Par exemple, le E de 2^10 est 10, donc lorsqu'il est stocké sous forme de nombre à virgule flottante 32 bits, il doit être stocké sous la forme 10+127=137, c'est-à-dire 10001001

3.5.2 Régulation de E lors de l'extraction depuis la mémoire

1. E n'est pas tout à 0 ou pas tout à 1

  • 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 de 127 (ou 1023) pour obtenir la valeur réelle, puis le nombre significatif M est ajouté au premier 1
  • Par exemple : la forme binaire de 0,5 (1/2) est 0,1, car 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 de commande est -1+127= 126, représenté par 01111110
  • Si la mantisse 1.0 supprime la partie entière comme 0, et remplit 0 à 23 chiffres de 0000000000000000000000, alors sa
    représentation binaire est 0 01111110 0000000000000000000000

2. E est tout 0

  • L'exposant E du nombre à virgule flottante est égal à 1-127 (ou 1-1023) est la valeur réelle
  • Le chiffre significatif M ne s'ajoute plus au premier 1, mais est réduit à une décimale de 0,xxxxxx. Ceci est fait pour représenter ± 0, et de très petits nombres proches de 0

3. E est tout 1

  • Si les chiffres significatifs M sont tous 0, cela signifie ± l'infini (positif ou négatif dépend du bit de signe s)

3.6 Exemple 1

int main()
{
    
    
	float f = 5.5; //浮点数
	101.1 二进制表示
	(-1)^0 * 1.011* 2^2 IEEE 745规定
	s=0 //代表正数
	E=2  //代表指数,左移2位  ,存储是时要+127 =129
	M=1.011 //有效数字
	0 10000001 01100000000000000000000
	0100 0000 1011 0000 0000 0000 0000 0000
	0x40 b0 00 00 小端存储
}

Il ressort de l'analyse ci-dessus que la forme de stockage du nombre à virgule flottante 5.5 en mémoire est illustrée dans la figure suivante : le
insérez la description de l'image ici
débogueur a trouvé que le résultat est cohérent avec le processus d'analyse et il est stocké en petit boutiste.
insérez la description de l'image ici

3.7 Exemple 2

int main()
{
    
    
	float f = 0.5; 浮点数
	0.1 二进制表示
	(-1)^0 * 1.0*2^-1 IEEE 745规定
	S = 0   代表正数
	M = 1.0  有效数字
	E = -1   代表指数,右移1位  ,存储是要+127 =126
	0 01111110 00000000000000000000000
	0011 1111 0000 0000 0000 0000 0000 0000
	0x3f 00 00 00
	
	return 0;
}

Il ressort de l'analyse ci-dessus que la forme de stockage du nombre à virgule flottante 0,5 en mémoire est illustrée dans la figure suivante : le
insérez la description de l'image ici
débogueur a trouvé que le résultat est cohérent avec le processus d'analyse et il est stocké en petit boutiste.
insérez la description de l'image ici

3.8 Exemple 3

Voici un exemple de 3.1 pour expliquer :

int main()
{
    
    
	int n = 9;
	第一步:正数9在内存存储的形式:
	00000000000000000000000000001001
	float *pFloat = (float*)&n;
	第二步:将正数强制转换位浮点型,认为pfloat指向的内容是浮点数
	存储在内存中的形式
	0 00000000 00000000000000000001001
	0000 0000 0000 0000 0000 1001
	0x00 00 00 09
	s=0
	E= -126  因为E是全为0的特殊情况,取出就是1-127固定的
	M= 0.00000000000000000001001 后面23位都是小数位
	第三步:从内存中取出浮点数
	(-1^0 * 0.00000000000000000001001 * 2^-126 
	结果为极限接近0的非常小的数
	printf("n的值为:%d\n",n); 输出9
	printf("*pFloat的值为:%f\n",*pFloat);输出浮点数0.00000
	
	*pFloat = 9.0;
	第一步:浮点数9.0的二进制形式:
	1001.0
	(-1)^0 * 1.001 * 2^3
	s=0
	E=3   代表指数,左移3位  ,存储是要+127 =130
	M=1.001
    第二步:浮点数9.0在内存存储的形式:
    0 10000010 00100000000000000000000
    0100 0001 0001 0000 0000 0000 0000
    0x41 10 00 00
    第三步:%d打印,上面的补码就是正数的补码了,三码合一
    打印原码: 1,091,567,616
	printf("num的值为:%d\n",n);
	printf("*pFloat的值为:%f\n",*pFloat); 9.0
	return 0;
}

À ce stade, en regardant les résultats, il sera clair en un coup d'œil :

- Sortie du nombre à virgule flottante 0,00000, nombre à virgule flottante sous forme de stockage en mémoire 0x00 00 00 09, forme de stockage little endian :
insérez la description de l'image ici

  • Le nombre positif de sortie 1 091 567 616, le nombre positif est stocké en mémoire sous la forme 0x41 10 00 00, et au format de stockage little-endian :
    insérez la description de l'image ici
    le résultat de sortie est cohérent avec l'analyse :
    insérez la description de l'image ici

3.9 Déterminer si deux nombres à virgule flottante sont égaux ?

Deux nombres à virgule flottante ne peuvent pas être jugés directement s'ils sont égaux ou non. Il convient de juger si la différence entre eux se situe dans une plage donnée, qui peut répondre à leurs propres exigences d'utilisation.

int main()
{
    
    
	int a = 0;
	if (a == 1)//整数可以直接判断
	{
    
    

	}
	float b = 0.00001;//基本接近0,但不是0
	if (b==0.0)//不能这样判断,会出问题
	{
    
    

	}
}

Résumer

Le contenu lié au stockage des données est le premier point de connaissance au stade avancé du langage C. Il est étroitement lié à l' amélioration de la mise en forme . Il est également nécessaire de se familiariser avec les types de variables, les bits de signe, les plages de types, le complément de code d'origine. , etc. Cette partie du contenu est plus Gardez à l'esprit la nature du type de stockage variable, vous ne pouvez pas tenir les résultats pour acquis, et chaque étape de la réflexion doit être basée sur celui-ci .

Il faut revoir l'ancien et apprendre le nouveau , et à travers cette partie de l'étude, se donner une idée différente du futur programme pour trouver les erreurs.

Le prochain article commence à apprendre le contenu avancé des pointeurs.

Je suppose que tu aimes

Origine blog.csdn.net/taibudong1991/article/details/124045057
conseillé
Classement