计算机中实数的比较
最近被问到了实数与0为什么不能直接比较的问题,要想说清楚还真不容易。
这里从浮点数的表示、内存存储角度加以总结。
科学计数法
科学计数法表示十进制数的浮点数遵循了小数点前面只有一个数(1~9)的规则。
例如:
0.75的科学计数法为
。
浮点数在内存中的存储
根据IEEE国际标准,任意一个二进制浮点数可以表示为下面的形式:
(-1)^S*M*2^E
(-1)^S表示符号位,当S=0时,表示正数,当S=1时,表示负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。
二进制浮点数1011.0011的科学计数法为
IEEE 745规定:
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。
有效数字M:
1<M<2,也就是说,M写成1.xxxxxxx的形式,其中xxxxxxx表示小数部分。
而为了扩大M的取值范围,增加它的位数,IEEE 754规定,在计算机内部保存M时,因为浮点数的第一位总是1,可以被舍去,只保存小数部分,而在取出来时在添上。比如保存1.011时,只保存011,后面的位数补0就可以了,等到读取的时候,再把第一位的1补上去。
指数E:
首先,E为一个无符号整数(unsigned int)
如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法是可以出现负数的,所以IEEE 754又规定,存入内存的E是真实值加上一个中间数,对于8位的E,中间数是127,对于11位的E,中间数是1023。比如,2^2的E是2,所以保存为32位浮点数时,必须保存为2+127=129,即10000001。
两种特殊情况:
E全为0
E的二进制为全为0代表原来的E是-127,这意味着什么,2的127次方是一个无穷大的数,而1再除以127说明这个数已经无限趋近与0了。这时,浮点数的指数E等于1-127(或1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxxx的小数。这样做是为了表示正负零,以及接近于0的很小的数字。
E全为1
E的2进制全为1,11111111,也就是原来的E值为128,2的128次方是一个很大的数,因此我们也认为,有效数字M不再加上第一位的1,再加上符号位S,就表正负无穷大的数字了。
精度损失
计算机只识别0和1,而2的指数次幂不可能表示到所有的数,所以在浮点数存储时,不可能完全与原来的数一模一样。
因为M只有23位,而0.1的二进制远远不止23位,会发生截断,只取23位,这也就是为什么浮点型存储会有精度损失。
而精度损失造成的后果可能会变大也可能会变小,因为在存储截断也可能会发生四舍五入进位。
两个浮点数的比较
因为精度损失,两个浮点数也就不能用==来进行比较
而是通过两个浮点数差值的绝对值是否小于某个预先设定的误差值来判断。
浮点数与0的比较
一个浮点数减去0再与预设的误差相比就能判定是否等于0。
学习引用:
细谈浮点数与0的比较
细谈浮点数与0的比较_浮点数与0比较_海绵宝宝养的的小窝的博客-CSDN博客
float数据的计算近似问题
float数据的计算近似问题 - 知乎
特别感谢!