简单认识:
我们在浮点数中,采用IEEE 754标准,使每一个数都采用的方式来表示。
其中为符号位,S只能为 0 或 1 ,0表示这个数为正数,1表示负数。
M为有效数字位,也就是真实数经过小数点浮动后的数字,M的范围是1的闭区间至2的开区间,也就是1 ≤ M < 2。
E是指数位,表示的是小数点浮动的距离,如0b1110.1 = 1.1101 * 2^3,其中E为3。
举个例子:
flaot a = 5.5f;
转为2进制:101.1
其中,符号为正,则S为0。M需要满足1 ≤ M < 2,小数点需要向左移2位,则E为2,M为1.011。
现在我们知道了S、M、E表示的是什么,以及该如何表示了,现在我们再深入一点。
因为2种浮点数的大小不同,所以排列方式也按flaot和double分2种:
对于32位的浮点数(flaot),最高位的1位是符号位S,接着8位是指数E,剩下23位位有效数字M。
对于64位的浮点数(double),最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
存入
奇怪的E:
E的类型是无符号整型,也就是说,小数点只能往左移。但因为M的范围在1~2之间,所以我们还需要E可以为负数。如:0.5 == 0.1,此时小数点需要右移1位,也就使E == -1, 才可使M进入1 ≤ M < 2的范围。
所以我们约定,E存入内存的时候,flaot类型的数据自动+127(称为中间值)再存入,double类型的自动+1023再存入。
去头的M:
因为M的取值范围特质,它的个位一定是1。而为了使浮点数可以表示更大的值,我们M存的时候,直接去头,1.011直接变为011存入。这样我们小数点位就可以多存一位了。
利用上面这些,现在我们可以去看看5.5是怎么存的了。
flaot a = 5.5; 在内存中长什么样?
S为1,E为真实值2+中间数127 = 129, M为1.011
01000000101100000000000000000000
S E M
取出
取出时分3种情况。
1.E为全0时
我们知道E存进去的时候,实际上是“真值+中间值127(flaot类型)”,而想让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