浮点数在内存中的存储

浮点数在内存中的存储详解

我们知道, 计算机内部实际上只能存储或识别二进制。
在计算机中, 我们日常所使用的文档, 图片, 数字等, 在储存时, 实际上都要以二进制的形式存放在内存或硬盘中, 内存或硬盘就好像是一个被划分为许多小格子的容器, 其中每个小格子都只能盛放0或1。我们日常使用的 浮点数 也不例外, 最终也要被存储到这样的二进制小格子中。(来源于知乎)
对于整形来说:数据存放内存中其实存放的是补码。
那么,对于浮点数来说,在内存中是如何存储的呢?
浮点数在内存中的存储_第1张图片
首先,先来说一下浮点型数字的二进制怎么表示:
例如,5.5
前面的5为整数,表示为0101
后面的0.5等于2^(-1),二进制位0.1
故5.5的二进制为0101.1

下面,我给出一段代码,大家可以先自己思考以下输出的结果

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

思考完了吧!
浮点数在内存中的存储_第2张图片

下面请看结果:
浮点数在内存中的存储_第3张图片
相信大家可能都会对这个结果产生疑问,咋就是和我想得不一样呢?(本人真爱粉,不要黑我了啊哈哈哈哈)
浮点数在内存中的存储_第4张图片

各位莫急,听我说!

浮点数在内存中的存储_第5张图片

上⾯的代码中, num 和 *pFloat 在内存中明明是同⼀个数,为什么浮点数和整数的解读结果会差别这么⼤?要理解这个结果,⼀定要搞懂浮点数在计算机内部的表⽰⽅法。
*根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
V = (−1)^S M ∗ 2^E
• (−1)^S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
• M 表⽰有效数字,M是⼤于等于1,⼩于2的
• 2^E 表⽰指数位

例如:一个十进制数字5
二进制为 101.0 ,可以表示为 1.01×2^2
S=0 M=1.01 E=2

IEEE 754规定:

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

下面用图来理解以下上述的IEEE 754规定
浮点数在内存中的存储_第6张图片(图为32位)
浮点数在内存中的存储_第7张图片
(图为64位)

上面的IEEE 754 规定中我们提到,M的值是属于[1,2)(1到2的左闭右开区间),所以,M的值的小数点前的数只有可能是1,所以在存储的时候,M的表现形式就是" 1.XXXXXXX "默认就把1给省略了。
例如:保存1.01,保存的就只有01,小数点前的1就会省略,读取时把1加上去就可以了
浮点数在内存中的存储_第8张图片

这样就会节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保存24位有效数字。

接下来就到了指数E的讲解了,这个点比较重要,同时也比较复杂。
⾸先,E为⼀个⽆符号整数(unsigned int)

这意味着,如果E为8位,它的取值范围为0~ 255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的

例如:数字0.5,二进制为0.1,存储为浮点型,但是规定了M大于等于1,所以将小数点右移一位,他的存储形式就是(-1)^ 0 * 1.0*2^(-1),M中的1可以省略,故存为0,转换为23个0,E的值为-1,加上中间值127等于126,存为 01111 1110,存储如下图
浮点数在内存中的存储_第9张图片

所以IEEE 754规定,存⼊内存时E的真实值必须再加上这个指定的中间数,32位的条件下这个中间数就取为127;64位的条件下,这个中间数就取为1023。

例如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001
保存如下
浮点数在内存中的存储_第10张图片

此外,指数E还有一个重点,不能存储为全0或者全1!
废话不多说,以32位举例说明吧
例如,如果E存储为全0的话,就是说E加上中间数127后的二进制为0000 0000,大家可以想到指数E是-127,几乎趋近于0。
而存储全为1的话,就是指数E就是128,就会趋近于无穷大了

下面,我们带着知识点回到开头的练习,对其进行解析
浮点数在内存中的存储_第11张图片
首先,n为9,他的二进制为

0000 0000 0000 0000 0000 0000 0000 1001

因为9是正数,所以源码等于反码等于补码,故存储在内存中就是上述二进制序列
当9被以浮点型数字拆分,就为以下序列:

0 0000 0000 000 0000 0000 0000 0000 1001
//浮点数V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)

这个数趋近于零,故打印浮点型为0.000000

下面看第二部分,9的二进制为1001,v=(-1)^ 0*1.001 *2^3
E=3,E+127=130,M为1.001,省略小数点前的1,将001存入内存,后面补二十个零
E的二进制为

1000 0010

M的二进制位

001 0000 0000 0000 0000 0000 0000 

二进制序列位S+E+M
将浮点型数字9.0以存入内存,序列为

0 10000010 001 0000 0000 0000 0000 0000

当9以整形输出,因为为正数,所以直接将此二进制序列看作源码,用windows计算机算出十进制数值为1091567616
浮点数在内存中的存储_第12张图片
大家有空的话可以自己尝试着联系一下。
好了,阿豪今天的分享就到这了,点个关注不迷路哦!

你可能感兴趣的:(c语言,数据结构)