tips
1.
2.
浮点数内存存储方式与整型是截然不同,不可被整型思维带偏了
我用一个例子来理解浮点数在内存当中的表示方法,先上一个十进制浮点数13.5
1. 利用二进制的权重化为二进制浮点数
二进制权重表小数部分如下:
那么13.5(十进制浮点数)可以化为二进制浮点数1101.1。
因为1*2^0+1*2^2+1*2^3+1*2^(-1)=1+4+8+0.5=13.5
2. 将二进制浮点数化为 (-1)^S * M * 2^E 的形式
任意一个二进制浮点数V可以表示成这个形式:(-1)^S * M * 2^E
1. (-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。
2. M表示有效数字,大于等于1,小于2。
3. 2^E表示指数位。
1101.1化成这个形式便是:(-1)^0 * 1.1011 * 2 ^ 3
3. 标注变量SME并理清SEM在内存中的存储
1 8 23 (float)
1 11 52 (double)
4. 在内存中放入SEM
S
S的存储简单,只需要把S放在内存空间最开头的第一个字节里面就OK了
E(部分涉及到整型在内存里面的运算)
1. 首先,E为一个无符号整数(unsigned int),这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。
2. 但是,我们知道,科学计数法中的E是可以出现负数的,所以规定,存入内存时E的真实值必须再加上一个中间数:
1. 对于8位的E,这个中间数是127
2. 对于11位的E,这个中间数是1023
M
1. 前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
2. 规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的
xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
如1101.1在内存中如下存放:
5. 取出SEM并代入(-1)^S * M * 2^E 还原浮点数
E全为0
1. S不变。
2. 浮点数的指数E等于1-127(或者1-1023)即为真实值
3. 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数
E全为1
表示±无穷大(正负取决于符号位s)
E不全为0或不全为1
1. S不变。
2. 指数E的计算值减去127(或1023),得到真实值。
3. 有效数字M前加上第一位的1
解释原因
如下:
调试结果吻合预期:
需要特别注意的是:
1. 除非运气特别好,否则有很多浮点数都不能完美的,精确的被存储下来。因为利用二进制权重转化成二进制浮点数小数部分会非常困难与难凑,所以很多情况下,必然会造成精度的流失。
2. float类型的有效位M占23个字节,而double类型的有效位M占52个字节,这也就说明:double受精度流失的影响更小,因此更为精确。