C语言浮点数存储初步解析

我们已经知道了在C语言中每个类型的数据生成时都会在内存上开辟一个属于自己的空间从而存储,了解了基本的数据的存储后,我们来一起学习浮点数的存储方法;

浮点数的存储不同于任何一种数据的存储;

浮点数的存储方式十分特别,这与浮点数本身的数据特点有关;

在这里我们主要学习浮点数中的float 和 double 类型的存储。


我们通过一段代码来引入:

#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;
}

我们看完这段代码后,最初在心中是有一个答案的,不管正确与否;

结果:

结果为何会是这样?


要搞清楚为什么,我们一定要知道浮点数在内存上面的存储方式;

根据标准规定:任意一个二进制的浮点数可以表示V

V=( -1 )^S  *  M  * 2^E;
( -1 )^S表示这个浮点数的正负,S只能取0或1;M表示有效数字,其大小范围是:>=1&&<2;
2^E表示的指数位。(先不必过多去理解这些,我们通过举例来说明)
例如一个浮点数:5.0 首先我们要把它转换为二进制的:那么就是101.0,那么存储时,S就是0,M就是1.01,E就是2
即(-1)^0 *1.01 * 2^2;        这里的指数部分可以联想十进制的科学计数法来理解,比如1.101*10^3,还原的时候小数点就往后移动3位,在这里只不过换成了2进制。
当然我们为什么会说float是单精度的而double是双精度的呢?在这里对于32位的浮点数:
第一个比特位存储的就是S;
紧接着后面8个存储的是E;
接着的23个存储的是M;
对于64位的浮点数:
第一个比特位存储的是S;
紧接着后面11个比特位存储的是E;
后面52个比特位存储的是M;

在理解完上面的之后,在这里介绍有关存储的更为细节的地方:

对于M,我们已经知道了,它无论如何都有一个整数部分 1,那么有规定:存M的那些个比特位不在存储这个整数部分1,而是去存储M的小数部分,这样扩大了M的存储范围。原本存储23个的,实际上存储了24个;

对于E,首先声明它是一个无符号整数;这就规定了它范围要么是0~255,要么是0~2047;但是我们知道,科学计数法中E是可以为负数的,为了实现这一点,规定了E在存入内存的时候要加上127或者是1023;比如对于32位的浮点数,指数部分是2^6,那么E真实值是6,但是在存入的时候要加上一个中间值127;同理对于64位的,存入时要加上中间值1023。

浮点数取出来的过程:在这里E的情况很特别,我们具体来看指数部分E是如何取出来的:

第一种情况:在E不全为0或是不全为1的时候:直接减去127或者是1023就可以得到E的真实值;

第二种情况:在E全为0的时候:这时候取出就直接取E是(1-127)或者是(1-1023),同时,有效数字M也不再加上第一位的1,而是还原成0.xxxxxx的小数,这样是为了表示正负0,或者很接近于0的小数;

第三种情况:在E全是1的情况下:此时若有效数字M全为0,则表示正负无穷大,这里的正负号取决于S


回归到最初的那个代码:

#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;
}

我们看到n的地址被转换成float*的类型的那一行,通过上面的学习我们已经知道了flaot的存储方式,它是极其区别于int型的存储方式,在内存上,原本是:

00000000000000000000000000001001,指向这个值的指针类型被转换之后

第一个0是符号位,(-1)^0说明是正的,后8位全为0,那么取出来的时候,M不会加上1,也就是

000 0000 0000 0000 0000 1001,最后还原出来就是*pFloat=(-1)^0 *0.(17个0)1001 *2^-126
我们发现这是一个非常小的数字;也就可以写成0.000000;这是第二个打印;对于第一个打印,
以整数的格式化打印那么它还是整数,打印出来9(虽然存储方式变了,但是它还是那几个0和1在
那些3位置上摆着,此时用整型打印不会影响什么)
后面将值改为9.0,这时候是通过内存来赋值的,那么原本这些比特位存储的数字也就发生了变
化,9.0,首先转换成二进制就是:1001.0,即写成:(-1)^0* 1.001* 2^3,那么存入内存就是:
0 10000010(存入的时候加127,也即存入是130) 00100000 00000000 0000000
此时若是打印整数那就是一个内存为01000001000100000000000000000000的整型,可以计算,这个数值十分庞大,这就是第三个打印;
最后一个打印就是将我们上面分析的整改之后的存储值以浮点数的方式再取出,S就是0,E是130-127,M是1.001(这里E不全为0,所以是常规情况,M要加上隐形存储的1),取出来就是9.000000

本次分享结束啦,不解或是有任何问题都可以私信我哦!谢谢。

  • 32
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值