浮点数在内存中的存储详解
我们知道, 计算机内部实际上只能存储或识别二进制。
在计算机中, 我们日常所使用的文档, 图片, 数字等, 在储存时, 实际上都要以二进制的形式存放在内存或硬盘中, 内存或硬盘就好像是一个被划分为许多小格子的容器, 其中每个小格子都只能盛放0或1。我们日常使用的 浮点数 也不例外, 最终也要被存储到这样的二进制小格子中。(来源于知乎)
对于整形来说:数据存放内存中其实存放的是补码。
那么,对于浮点数来说,在内存中是如何存储的呢?
首先,先来说一下浮点型数字的二进制怎么表示:
例如,5.5
前面的5为整数,表示为0101
后面的0.5等于2^(-1),二进制位0.1
故5.5的二进制为0101.1
下面,我给出一段代码,大家可以先自己思考以下输出的结果
#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; }
思考完了吧!
下面请看结果:
相信大家可能都会对这个结果产生疑问,咋就是和我想得不一样呢?(本人真爱粉,不要黑我了啊哈哈哈哈)
各位莫急,听我说!
上⾯的代码中, 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规定
(图为32位)
(图为64位)
上面的IEEE 754 规定中我们提到,M的值是属于[1,2)(1到2的左闭右开区间),所以,M的值的小数点前的数只有可能是1,所以在存储的时候,M的表现形式就是" 1.XXXXXXX "默认就把1给省略了。
例如:保存1.01,保存的就只有01,小数点前的1就会省略,读取时把1加上去就可以了
这样就会节省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,存储如下图
所以IEEE 754规定,存⼊内存时E的真实值必须再加上这个指定的中间数,32位的条件下这个中间数就取为127;64位的条件下,这个中间数就取为1023。
例如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001
保存如下
此外,指数E还有一个重点,不能存储为全0或者全1!
废话不多说,以32位举例说明吧
例如,如果E存储为全0的话,就是说E加上中间数127后的二进制为0000 0000,大家可以想到指数E是-127,几乎趋近于0。
而存储全为1的话,就是指数E就是128,就会趋近于无穷大了
下面,我们带着知识点回到开头的练习,对其进行解析
首先,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
大家有空的话可以自己尝试着联系一下。
好了,阿豪今天的分享就到这了,点个关注不迷路哦!