浮点型在内存中的存储

上一篇博客中我们提到了整型在内存中的存储,而今天我们就来谈谈浮点型在内存中的存储。在这之前首先让我们来看一段代码,并猜测一下各自的输出:

#include <stdio.h>
int main()
{
	int a = 5;
	float* pf = (float*)&a;
	printf("%d\n", a);//1
	printf("%f\n", *pf);//2
	*pf = 5.0;
	printf("%d\n", a);//3
	printf("%f\n", *pf);//4
	return 0;
}

相信大部分人可能认为代码中编号1、2、3、4对应位置为5、5.000000、5、5.000000。但实际上这段代码的结果并非如此,以下是使用VS2022的运行结果:
在这里插入图片描述
可见,2与3的结果与我们的预期完全不同,这是为什么呢?通过观察原代码,我们可以发现main函数第二行将整型a的地址进行强制类型转换为了浮点型地址,并且编号3处将浮点数5.0以整型的格式打印,从而导致了2、3处的结果。以此,我们可以猜想浮点型在内存中的存储方式是否与整型不同?而事实正是如此,接下来我们便来看看浮点型在内存的存储方式。

浮点型的存储

根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰为以下的形式:
在这里插入图片描述
其中(-1)^S是符号位,S=0时V表示正数,S=1时V表示负数;M是有效数字,M的值是大于1而小于2的;
2^E则是指数位。
就拿先前的十进制数5.0来举例,用二进制可以表示为101.0,而按上面的公式表示为:1.01*2^2。其中S为0,M其实为01(这里后面会说明),E为2。
而在内存中就是将S、M、E这三个数以二进制形式按顺序存储在内存中,从而实现对浮点型V的存储。以下分别是float与double类型在内存中的存储格式与大小(单位:bit):
float:
在这里插入图片描述
float类型的大小是4个字节也就是32个比特位,其中第一个比特位存放S,S后的8个比特位存放E,而剩下的23个比特位便是存放有效位M.
double:
在这里插入图片描述
double类型的大小是8个字节也就是64个比特位,与float不同的是,double类型的E占11个比特位,M占52比特位。
至于有效位M,前面说过1<=M<2,也就是说M始终可以表示为1.###,因此在IEEE754规定计算机在存储M时默认将M的首位定为1,所以计算机便只需要存储小数点后面的数位到M处,等到使用时再把1加上去,这样便可以节省空间来存储更大的数字(是不是很巧妙)。这就是之前例子中1.01仅存储01的原因。
至于指数E,首先E为一个无符号整型,这也就意味着当E占8个比特位时的取值范围为0-255,占16个比特位时的取值范围为0-2047,但我们知道科学计数法的指数位是可以为负数的。因此,IEEE754又规定,存入E的真实值时必须加上一个中间值,对于8个比特位的E这个中间值为127,16个比特位时为1027,对于上面的5.0的例子,E处存放的就是127+2=129的二进制形式,也就是:1000 0001。
如何指数E还存在2种极端的情况:

E全为0

此时,浮点数的E的真实值等于1-127(或1-1023),而这时的M不在加上首位的1,变成了0.#####,这样做是为了表示±0,以及接近0的很小的数。

E全为1

这时,若M全为1,可以表示正负无穷大(正负取决于S)。

最后让我们回到一开始的那段代码的例子,为了方便主要代码显示如下:

int a = 5;
float* pf = (float*)&a;
printf("%d\n", a);
printf("%f\n", *pf);
*pf = 5.0;
printf("%d\n", a);
printf("%f\n", *pf);

代码上部分将整型a以浮点型的形式存放,其二进制序列表示如下:
在这里插入图片描述
符号位的S为0,指数位E也全为0,有效位M为0000 0000 0000 0000 0000 101,用公式表示相当于:
V=0.0000 0000 0000 0000 0000 101*2^(-126)。显然V会时一个非常小且接近于0的数,因此用十进制的小数表示就是0.000000。
代码下半部分则将浮点数5.0以整型格式进行输出,其二进制序列的转变如下:
在这里插入图片描述
作为整型二进制表示就成为了将S、E、M三部分结合。可见,将浮点数5.0的二进制表示形式以整型的进行表示会是一个相当大的数字,而这个二进制序列原码的十进制便是前面运行结果3的数字。

浮点型数据在内存存储方式是按照IEEE 754标准进行存储的。IEEE 754标准规定了两种浮点数的表示方法:单精度浮点数和双精度浮点数。其,单精度浮点数占用4个字节,双精度浮点数占用8个字节。 在IEEE 754标准,浮点数的存储格式由三部分组成:符号位、指数位和尾数位。其,符号位用来表示浮点数的正负,指数位用来表示浮点数的数量级,尾数位用来表示浮点数的精度。 具体来说,单精度浮点数的存储格式如下所示: | 31 | 30 - 23 | 22 - 0 | |----|---------|--------| | S | E | M | 其,S表示符号位,占用1个bit;E表示指数位,占用8个bit;M表示尾数位,占用23个bit。双精度浮点数的存储格式类似,只是指数位和尾数位的长度不同。 在计算机,浮点数的存储方式是按照二进制补码进行存储的。具体来说,符号位用0表示正数,用1表示负数;指数位和尾数位都用二进制补码表示。 举个例子,如果要将3.14这个单精度浮点数存储到计算机,首先需要将3.14转换成二进制数。具体来说,可以使用以下方法进行转换: 3.14 = 11.0010001111...(二进制) 然后,根据IEEE 754标准的规定,将上述二进制数按照符号位、指数位和尾数位的顺序存储到计算机。具体来说,可以将上述二进制数转换成以下形式: | 0 | 10000000 | 10001100100011110101110 | |---|----------|------------------------| | S | E | M | 其,符号位S为0,表示正数;指数位E为10000000,表示指数为128(因为E需要加上一个固定的偏移量127,才能表示实际的指数值);尾数位M为10001100100011110101110,表示尾数为1.5707964(因为M需要除以2的23次方,才能表示实际的尾数值)。 因此,3.14这个单精度浮点数在计算机存储方式为: 01000000000100110010001111010111
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值