简单认识:

我们在浮点数中,采用IEEE 754标准,使每一个数都采用【浮点数】在内存中的存储与取出_浮点数的方式来表示。

其中【浮点数】在内存中的存储与取出_数位_02为符号位,S只能为 0 或 1 ,0表示这个数为正数,1表示负数。

M为有效数字位,也就是真实数经过小数点浮动后的数字,M的范围是1的闭区间至2的开区间,也就是1 ≤ M < 2。

E是指数位,表示的是小数点浮动的距离,如0b1110.1 = 1.1101 * 2^3,其中E为3。

举个例子:

float a = 5.5f;

转为2进制:101.1

其中,符号为正,则S为0。M需要满足1 ≤ M < 2,小数点需要向左移2位,则E为2,M为1.011。

现在我们知道了S、M、E表示的是什么,以及该如何表示了,现在我们再深入一点。

因为2种浮点数的大小不同,所以排列方式也按float和double分2种:

对于32位的浮点数(float),最高位的1位是符号位S,接着8位是指数E,剩下23位位有效数字M。

【浮点数】在内存中的存储与取出_浮点数_03

对于64位的浮点数(double),最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。

【浮点数】在内存中的存储与取出_浮点数_04



存入

奇怪的E:

E的类型是无符号整型,也就是说,小数点只能往左移。但因为M的范围在1~2之间,所以我们还需要E可以为负数。如:0.5 == 0.1,此时小数点需要右移1位,也就使E  == -1, 才可使M进入1 ≤ M < 2的范围。

所以我们约定,E存入内存的时候,float类型的数据自动+127(称为中间值)再存入,double类型的自动+1023再存入。


去头的M:

因为M的取值范围特质,它的个位一定是1。而为了使浮点数可以表示更大的值,我们M存的时候,直接去头,1.011直接变为011存入。这样我们小数点位就可以多存一位了。

利用上面这些,现在我们可以去看看5.5是怎么存的了。


float a = 5.5; 在内存中长什么样?

S为1,E为真实值2+中间数127 = 129, M为1.011

01000000101100000000000000000000

     E                          M


取出

取出时分3种情况。

1.E为全0时

我们知道E存进去的时候,实际上是“真值+中间值127(float类型)”,而想让E为全0,则真实值一定小于等于-127,这样这个数其实是接近无穷小的。

所以我们直接将E视为1-127(double为1-1023),M取出时,小数点前直接补0。最终这个数打印出来的结果就是0.000000


2.E为全1时

此时E的真实值大于等于128,我们将E直接视为一个无穷大的数(正负取决与符号位S)


3.E为有0有1时

此时E减去中间值,然后M补上小数点及小数点前面的1,直接取出, 再由S决定正负。

如,

01000000101100000000000000000000

符号位0,表示正数,

指数位10000001-01111111 == 00000010

有效数为011,前面补1与小数点,为1.011

连起来就是 1.011*(2^2) == 0b101.1 == 5.5