1.引子
通过上图,我们发现即使是在我们看来字节大小、实际意义一样的数据,以浮点数、整数两种不同的形式进行存放、取出结果是不同的值,这就说明计算机对浮点数与整数是完全不同的处理方式。毕竟我们都知道计算机是只能识别二进制,因此如何表示小数以及用科学计数法表示数中的点后数以及10的次方就是个值得仔细规划的问题。
2.浮点数的存储
1.浮点数转化为二进制
与整数一样,浮点数也可以根据2的权重转换成二进制,后面乘对应的2的次方即是科学计数法的表示形式
类似于十进制下浮点移动,后面乘上对应10的次方,二进制下科学计数法也是如此,上图101.1还可以进一步化成如下形式
2.S、M、E的存储空间规定
如果我们仔细思考就会发现所有的浮点数都可以表示成这样形式,那么唯一在变的其实就是S、M、E,因此浮点数我们只要存储好这三者就行了。
3.浮点数的存入的特殊规定
1.针对M的特殊规定
前文说过任何数都可以表示成类似科学计数法的表示形式,M必然是1.xxxxx的形式,那么在存储的时候,1其实就显得多余了,因此存储的时候1.xxxx的‘1’就是默认存在的,省略不存,内存中只会存入后面的.xxxxx的部分,如1.01,最终只会存入01,取出的时候将前面的‘1’加上,这样存就会多出1bite的空间,我们存储的精度就更大了。
2.针对E的特殊规定
首先E被规定无符号整数,这意味E为8位,那么它的取值范围是0~255,如果是11位,那么它的取值是0~2047,但是我们知道科学计数法的指数位应该是可以出现负数的,所以IEEE 754规定存入时必须加上一个中间数,对于8位的E,这个中间数就是127;对于11位的E,这个数就是1023.如存储2^10,E为10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
注:对于有效位数为0的情况,我们要可以用0补齐到M对应存储位。如0.5 的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其阶码为-1+127(中间值)=126,表⽰为01111110,⽽尾数1.0去掉整数部分为0,补⻬0到23位,如以下形式:
0 0111111000000000000000000000000
(因为从左往右2的权重是逐渐减小的,0是加载数字后面的)。
4.浮点数特殊的取出规定
1.E不全为0或1的情况:
将解码减去对应127或者1023得到E,再将有效数字M前面补上1,最后根据S判断数据的正负。
2.E全为0:
E为全0,则E的真实值为-127,则源数据为
,这是一个无限接近于0的数,实际就为0.xxxxxxxxxx,因此规定1-127即为真实值E,有效数字M不再加上第⼀位的1,而是还原为0.xxxxxx的⼩数。这样就表示了表⽰±0,以及接近于0的很⼩的数字。
3.E为全1
这是阶数很大,如果有效数字M全为0,则表⽰±⽆穷⼤(正负取决于符号位s);
注:因为E是unsigned int 所以E仍然存在取值范围,不可能表示出所有数。
3.浮点数存储精度
1.精度丢失
其实上述的存储看似万无一失,但是当我们多输入一些数字
我们会发现当精度特别小的时候,我们的数值看起来就变不太一样了,因为其实二进制表示十进制时,对于0.xxxx后面的xxxxx部分是通过2的负次方来表示的,但是这种表示方法就会出现部分数无论怎么往后凑,都会差一点,甚至无限下去,因此,有的浮点数实际上计算机跟我们人看到的不一样,对于这些数,计算机会根据精度来确定数字具体多少。如0.1,如精度只有0.1,那它就是0.1,但是当精度到0.50时,它就不是0.1了。
2.浮点数的比较
因为前面说的精度丢失问题,浮点数间不能用==直接比较大小
那么针对这种情况,我们该如何比较呢?浮点数只能使用差值与规定精度进行比较