数据在内存中的存储.2(浮点型)

系列文章目录

数据在内存中的存储.1


目录

系列文章目录

前言

一、浮点型和整型在内存中的存储方式是否相同

二、浮点型在内存中的存储方式

1.浮点数存储规则

2.对E进行分析

3.E从内存中取出

1>   E不为全0或不为全1

2>   E全为0

3>   E全为1

三、题解



前言

研究浮点型数字在内存中的存储方式,观察其与整型存储的方式有何不同。


一、浮点型和整型在内存中的存储方式是否相同

先来看一段代码及其运行结果

#define _CRT_SECURE_NO_WARNINGS
#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("num的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	return 0;
}

运行结果如下图:

这与我们所期望的值不同,但是什么原因导致的呢?

(整型与浮点型在内存中的存储方式不同)

二、浮点型在内存中的存储方式

1.浮点数存储规则

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

1>   (-1)^S*M*2^E

2>   (-1)^S表示符号位,当S=0,V=正数;S=1时V=负数

3>   M代表有效数字,大于等于1,小于等于2;

4>   2^E表示指数位

以十进制小数5.5为例,其转换成二进制后表示为101.1,下图是二进制中各位所占的权重

 可见,小数点右边的权重时从2的负一次方到2的负n次方减少的。

再以十进制数字5.5为例:

其转化为十进制后为101.1  ,用科学计数法表示后为1.011*2^2

再根据上方的浮点数表示方法可知 十进制数字5.5可表示为

(-1)^0   *1.011   *2^2

符号位S=0  M=1.011  E=2

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

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

2.对E进行分析

E的情况稍微有些复杂,E为一个无符号的整数

当E为8位时它的取值是0-255如果E为11位,它的取值范围为0-2047,但是E用科学计数法表示,是可以出现负数的,所以在IEEE 754中规定存入内存时E的真实值必须再加上一个中间数,对于8位的E这个中间数位127;对于11位的E中间数为1023。

例如2^10的E为10,则32位浮点数中保存为10+127=137,用二进制表示为:10001001


继续以十进制数字5.5为例

32位浮点数存储下

(-1)^0   *1.011   *2^2

符号位S=0  M=1.011  E=2

E+127=129,129的二进制表示为10000001

则5.5表示为

0100 0000 1011 0000 0000 0000 0000 0000

转化为十六进制

4        0         b       0      0        0       0       0

究竟是不是这样存储的呢?

我们在Vs中进行调试:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	float f = 5.5;
	return 0;
}

这是f在小端存储(何为小端存储?)下的存储形式,f应为40 b0 00 00存储,验证了我们的推测是正确的;

既然我们知道了浮点数是如何在内存中存储的,那我们也应该知道浮点数如何从内存中取出来

3.E从内存中取出

指数E从内存中取出还可以再分为三种情况:

1>   E不为全0或不为全1

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

2>   E全为0

那么原来的指数加上127等于0;则真实值为-127,此时该浮点数接近0.

(-1)^s*0.xxxxxx*2^-127

所以规定浮点数的指数E等于1-127(或1-1023)为真实值,目有效数字M不再加上第一位的1,这样做的目的是为了表示正负0,以及接近于0的很小的数字

3>   E全为1

E中存储的数为255,则其真实值为128

(-1)^s*M*2^128,为很大的数字

此时这个数字为正无穷或负无穷正负号取决于符号位s


三、题解

有了上述的铺垫,文章开头的代码运行结果也能得到解释了

#define _CRT_SECURE_NO_WARNINGS
#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("num的值为:%d\n", n);
	printf("*pFloat的值为:%f\n", *pFloat);
	return 0;
}

先来看第二行输出的结果为什么为0.000000

32位机器下9的二进制序列

00000000000000000000000000001001

但是是以%f的形式即以浮点数的形式打印的

0   00000000   00000000000000000001001

S       E                    M

很明显E中全为0

这个数字可以表示为

(-1)^0*0.00000000000000000001001*2^-126,无限接近于0.

再来看看第三个为什么输出结果为1091567616

此时的num是用打印整型的方式去打印一个浮点型的数字

*pFloat=9.0

1001.0//二进制表示

1.001*2^3//浮点数

(-1)^0*1.001*2^3//浮点数

S=0  E=3   M=1.001

0 10000010 00100000000000000000000

此时这个二进制序列是以整型形式打印出来的,存储的是二进制的补码(有符号位)

 观察该数字的十进制,与运行结果中一致,我们的疑惑得到解决。

创作不易留下你的赞吧2333333~

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值