您现在的位置是:首页 >其他 >C语言之浮点型在内存中的存储网站首页其他

C语言之浮点型在内存中的存储

Wsys1mple 2024-08-14 12:01:03
简介C语言之浮点型在内存中的存储

?博主CSDN主页:Wsys1mple?


?分类专栏:C语言初阶?


?gitee代码仓库:Wsys1mple的代码仓库?


?关注我,持续更新更多学习分享?


目录

1. 前言?

2. 浮点数存储和整形存储的区别?

3. 浮点数存储规则?

4. IEEE 754对M的特别规定?

5. IEEE 754对E的特别规定?

6. 指数E从内存中取出的三种情况?

6.1 E不全为0或不全为1✨

6.2 E全为0✨

6.3 E全为1✨

7. 解释浮点数存储的例子?

8. 总结?


1. 前言?

这里我们将深度剖析浮点型在内存中的存储,希望我的文章对你有所帮助。


常见的浮点数:

3.1415926

2E10(2乘以10的10次方)

浮点数家族包括:float、double、long double 类型。

其中浮点数的表示范围在 float.h 文件中定义

2. 浮点数存储和整形存储的区别?

我们先看一个浮点数存储的例子:

int main()
{
	int n = 9;
    float* pFloat = (float*)&n;

	printf("n的值为:%d
", n);//9
	printf("*pFloat的值为:%f
", *pFloat);//0.000000

	*pFloat = 9.0;
	
	printf("num的值为:%d
", n);//1091567616
	printf("*pFliat的值为:%f
", *pFloat);//9.000000

	return 0;
}

输出的结果:

为什么是这样呢?num 和 *float 在内存中明明是同一个数,而实际的结果是 *pfloat 的值变成了0.000000,num 的值变成了一个特别大的值,似乎并不符合常理。

我们带着疑问,继续学习以下内容。


3. 浮点数存储规则?

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:

  • (-1)^S * M * 2^E
  • (-1)^S表示符号位,当S=0时,V为正数;当S=1时,V是负数。
  •  M表示有效数字,并且取值范围是大于等于1,小于2。
  •  2^E表示指数位

举例来说:

十进制的 5.0,写成二进制是 101.0,相当于 1.01 * 2^2。

按照上面的格式,可以得到 S=1,M=1.01,,E=2。

同理,十进制的 -5.0,写成二进制是 -101.0,相当于 -1.01 * 2^2。

按照上面的格式,可以得到 S=0,M=1.01,E=2。

IEEE 754规定:

对于32位的浮点数,最高位是符号位S,接着的8位是指数E,剩下的23位是有效数字M。

对于64位的浮点数,最高位是符号位S,接着的11位是指数E,剩下的52位是有效数字M。

注意:对于所有的浮点数,都可以用 S,E,M表示,因此在内存中存储S,E,M相当于存储了浮点数。


4. IEEE 754对M的特别规定?

前面提到有效数字 M 的取值范围是大于等于1,小于2,也就是说 M 可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。

IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的小数部分。

举例来说:

保存1.01时,只保存01,等到读取的时候,再把首位的1加上去。

这样的目的是节省1位有效数字。以32位浮点数为例,M有23位,将首位的1舍去以后,等于可以存储24位有效数字。


5. IEEE 754对E的特别规定?

首先,E为一个无符号整数 (unsigned int)

E如果是8位,取值范围为0~255;E如果是11位,取值范围为0~2047。但是科学计数法中的E可以出现负数(指数出现负数),所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数

对于8位的E,这个中间数是127(例如E为-127,加上中间数127后值为0,这样才符合无符号整数的取值范围),对于11位的E,这个中间数是1023。

举例来说:

2^10的E是10,在保存成32位浮点数时,必须保存成10+127=137,即10001001。


6. 指数E从内存中取出的三种情况?

6.1 E不全为0或不全为1✨

指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。

举例来说:

0.5的二进制形式为0.1,由于规定正数部分必须为1,所以将小数点向右移1位,则为

1.0 * 2^(-1)  ,阶码()为-1+127=126,表示为01111110,尾数1.0去掉整数部分为0,二进制表示形式为:

0 01111110 000000000000000000000

(阶码:对于任意一个二进制数N,可用N=S×2^P表示,其中S为尾数,P为阶码,2为阶码的底,P、S都用二进制数表示,S表示N的全部有效数字,P指明小数点的位置。 当阶码为固定值时,数的这种表示法称为定点表示,这样的数称为“ 定点数 ”;当阶码为可变时,数的这种表示法称为 浮点 表示,这样的数称为“ 浮点数 ”。

阶码:在机器中表示一个浮点数时需要给出指数,这个指数用整数形式表示,这个整数叫做阶码。)


6.2 E全为0✨

这时,指数E等于1-127(即-126) (或者1-1023(即-1022))即为真实值,有效数字M不再加上第一位的1,而是还原为0,xxxxxx的小数,这样做是为了表示±0,以及接近于0的很小的数字。


6.3 E全为1✨

这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)。


7. 解释浮点数存储的例子?

int main()
{
	int n = 9;

	//0   00000000     00000000000000000001001
	//S   E            M
	//E全为0时,浮点数的指数等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数
	//即S=0 E=-126   M=0.00000000000000000001001
	//则为(-1)^0 * 0.00000000000000000001001 * 2^-126
	float* pFloat = (float*)&n;

	printf("n的值为:%d
", n);//9
	printf("*pFloat的值为:%f
", *pFloat);//0.000000

	*pFloat = 9.0;
	//1001.0
	//(-1)^0 * 1.001 * 2^3
	//得到S=0 E=3 M=1.001
	//存的时候E加上中间数127为130
	//则二进制表示形式为0 10000010 00100000000000000000000
	printf("num的值为:%d
", n);//1091567616
	printf("*pFliat的值为:%f
", *pFloat);//9.000000

	return 0;
}

8. 总结?

对于浮点型在内存中的存储,做到知道是怎么存的就足够了,不用死记硬背。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。