我们都知道整数在内存中是以二进制补码的形式进行存储,那浮点数也是与整数这样的方式进行存储吗?
我做了如下测试:
通过上面测试能看出整数和浮点数的存储方式有所不同。
接下来我来讲解float和double在内存中的存储。
我们都知道float(单精度浮点数)类型的数据在内存中占4个字节(32bit),而double(双精度浮点数)类型的数据在内存中占8个字节(64bit)这里也可以看出它们的存储也会有所不同。
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
V=(-1)^S * M * 2^E
(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。
M表示有效数字,大于等于1,小于2。(尾数位)
2^E表示指数位。
举例来说:
十进制的10.0,写成二进制是 1010.0 ,相当于 1.01×2^23。 那么,按照上面V的格式,可以得出S=0,M=1.01,E=3。
十进制的-10.0,写成二进制是 -1010.0 ,相当于 -1.01×2^3 。那么,S=1,M=1.01,E=3。
二进制小数点后表示2^(-N),所以浮点数是有可能无法精确到每一位的。
十进制的0.75,写成二进制是0.11,相当于1.1*2^(-1).S=0,M=1.1,E=-1。
十进制的-0.75,写成二进制是0.11,相当于-1.1*2^(-1).S=1,M=1.1,E=-1。
从上面可以看出1≤M<2
M
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的 xxxxxx部分。比如保存1.01的时 候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位 浮点数为例,留给M只有23位, 将第一位的1舍去以后,等于可以保存24位有效数字。
E
至于指数E,情况就比较复杂。 首先,E为一个无符号整数(unsigned int) 这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们 知道,科学计数法中的E是可以出 现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数 是127;对于11位的E,这个中间 数是1023。
当E全为0时:这时,浮点数的指数E等于1-127(或者1-1023)即为真实值。无限接近于0.
当E全为1时:这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)。
比如,2^5的E是5,所以保存成32位浮点数时,必须保存成 5+127=132,即 10000100。保存成64位浮点数时必须保存成 5+1023=1028,即010000000100;
这里我大概就将浮点数的存储方式讲清楚了,我们再来看上面的测试。
整数9的二进制存储是 0000 0000 0000 0000 0000 0000 0000 1001。
在浮点数看来:其中S为0,E也为0,M是000 0000 0000 0000 0000 1001
V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)(无限接近于0)由于float正常情况下保留小数后位,所以这里看作是0。
而浮点数9.0f二进制表示为1001.0=(-1)^0×1.001×2^130,E=3+127;
这里二进制表示为 0 10000010 00100000000000000000000
最后等于1,091,567,616