浮点数在内存中的存储——C语言

在数据类型中,浮点数也是很常见的,而对于浮点数的类型也多种多样:有double、float、long double类型。

一  代码示例

相对与整型在内存中的存储方式,浮点数却不相同,让我们以下列的代码为例子:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
	int num = 9;
	float* p = (float*)&num;
	printf("%d\n", num);
	printf("%f\n", *p);
	*p = 9.0;
	printf("%d\n", num);
	printf("%.1f\n", *p);
}

初看变量num,通过强制转换成float类型再通过指针解引用输出,但不能输出9的浮点数,而打印输出整型确实正确的。

当我们通过指针修改p中的数据成浮点数时,此时两者状况相反:

对于这种情况的出现,是因为浮点型与整型在内存中存储的方式不一样所导致的。

二  浮点数存储的规定

        num与*p明明存放的是同一个数,为什么用整型与浮点型的解读会出现不一样的效果?下面先让我们来了解一下浮点数在计算机中的表现形式:

我们知道,数据在计算机中是用0和1进行存储的,

根据国际标准IEEE754,任意一个二进制的浮点数V可以表示成下列形式:

V  =  (-1) ^ S  *M  *  2 ^ E

(-1)^S表示符号位,当s为1时,表示V是正数,当S为0时,表示V为负数。 

M表示有效数字,M的取值范围是1<=M<2。

2^E表示指数位。

这其实相当于科学计数法,以 314 * 10^3为例:

因为134 * 10^3是一个正数,所以s等于0;

因为有效数字M的范围是1<=M<2,所以我们134的整数点需要向前移动两位,所以134 * 10^3变成了1.34*10^5,E的大小为10。

用进制举例也是一样的:

以十进制的-5.0为例,转换成二进制为-101.0,用上面的办法,可以将V写成:

V=(-1)^1  * 1.01  * 2 ^ 2

S的值为1,有效值M为1.01,指数位E的大小为2。

当我们将这些数放在内存中时,V存放的顺序并不是按照S-M-E的顺序进行存放。

在IEEE754中规定:

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

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

内存图示如下: 

 

三  浮点数的存 

当浮点数进行存储时,对于M与E,IEEE754还有些规定。

对于有效数字M,因为1<=M<2,所以M可以写成1.xxxxxxxxx的形式,其中xxxxxxxxx表示小数部分,当M存于内存时,计算机会自动默认第一位数是1,因此在计算机中可以省略,只存储小数部分,当我们取出浮点数时,只需要再将第一位的1加上去即可。这样的好处是有效数字可以多存一位有效数字,以32位机器为例,原本M可以存储23位,现在可以存24位。

对于指数位E,情况就特殊许多了,首先我们需要一个清醒的认识:E是一个无符号整数。

如果E为8位,那么它的取值范围是0-255;如果E为11位,那么它的取值范围是0-2047;但是再科学计数法中,E是可以为负数的,因此IEEE规定,存入内存的E的真实值需要加上一个中间数。

对于8位的E,中间数是127;对于16位的E,中间数是1023。

一句话来说:

E+中间数  再存入内存!

比如:2^3的E是3,保存成32位浮点数时,那么存入内存的就是3+127=130,

转换成二进制就是1000 0010。

四  浮点数的取

对于指数E,在内存中取的情况也有三种:全为1,全为0,不全为1或不全为0。

情况1:E全为1

如果这时有效数字M全为0,表示+-无穷大(符号取决于S)。

情况2:E全为0 

浮点数的指数E等于1-127(或1-1023)即是真实值,有效数字M不再加上第一位的1,而是还原成0.XXXXX的小数,。这样做是为了表示+-0,以及接近与0的数字。

情况3:E不全为1或不全为0

这时指数E等于1-127(或1-1023)获得真实值,再将有效数字M前加上第一位1。

 五  回归代码示例

此时再让我们回到代码示例中:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
	int num = 9;
	float* p = (float*)&num;
	printf("%d\n", num);
	printf("%f\n", *p);
	*p = 9.0;
	printf("%d\n", num);
	printf("%.1f\n", *p);
}

因为num刚开始是以整型的形式进行存储,在内存中的二进制表示为:

1 0000 0000 0000 0000 0000 0000 0000 1001 

如果按照浮点型的形式进行拆分,符号位S=0;后面八位代表E,E=00000000,剩下的23位有效数字M是000 0000 0000 0000 0000 1001 ,符合E全为0的情况,所以V是一个接近于0的数字,所以用十进制小数表示就是0.000000。

再看浮点数9.0,整数的打印为什么是1091567616

那么先让我们将9.0在内存中的存放:

9.0的二进制数是1001.0,换算成科学计数法是1.001*10^3,

V=(-1)^0 *1.001 *2^3

对于32位浮点数,符号位为0,

指数位E存放进内存中实际上是3+127=130,转换成二进制是10000010,有效数字自动省略第一位的1,后面再加20位0凑够23位,那么有效位置的二进制是 001 0000 0000 0000 0000 0000

那么最后以浮点型存放进内存的二进制码为:

 10000010    001 0000 0000 0000 0000 0000

 

在计算器中转换成十进制时,得出的结果刚好是 1091567616,也就是我们通过整型读取浮点型的结果。

感谢观看,希望这篇文章能帮助到您了解浮点型的存储。

如果文章有错误或不足之处还请联系更正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值