目录
引言
有趣的现象
精度损失
两个浮点数的比较
浮点数与0的比较
总结
引言
在细谈浮点数与0比较之前,我们要引入一个小概念“浮点数是如何存储的”,我们知道整型在计算机中存储的是二进制,那么浮点数呢,是否也一样呢?我们看个例子:
int main()
{
int n = 9;
float *pfloat = (float*)&n;
printf("n的值为:%d\n", n);
printf("*pfloat的值为:%f\n", *pfloat);
*pfloat = 9.0;
printf("n的值为:%d\n", n);
printf("*pfloat的值为:%f\n", *pfloat);
return 0;
}
猜猜这些会分别输出什么?
明明*pfloat存储的与n存的值一样,但打印出来却相差这么多,这是因为浮点型与整型存储方式不同。
根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数可以表示为下面的形式:
(-1)^S*M*2^E
1.(-1)^S表示符号位,当S=0时,表示正数,当S=1时,表示负数。
2.M表示有效数字,大于等于1,小于2。
3.2^E表示指数位。
如:9.0可表示为1001.0
0.5可表示为0.1,注意这里小数点前直接按照二进制写出,小数点后为2的-n次方,n表小数点后的第几位。再比如0.125可表示为0.001。
IEEE 745规定:对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
IEEE 754对有效数字M和指数E,还有一些特别规定。
有效数字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还有两种特殊情况:
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,就表正负无穷大的数字了。
于是我们回到原来的例题。
再打开我们的计算器与之前的对比
发现结果就是这个,那么浮点型存储讲完。
有趣的现象
在偶然试验中,我定义了一个double类型的数观察它后50位的数字发现差距很大:
于是我们又引入了一个概念,精度损失。
精度损失
精度:精度是引起数据变化的最小值。
我们查阅资料发现float的精度为6位,double的精度为15位。这是为什么呢,因为在浮点数存储时,它不可能完全与原来的数一模一样,计算机只识别0和1,而2的指数次幂它不可能表示到所有的数。举个例子,用刚讲的浮点型存储表达0.1:
因为M只有23位,而0.1的二进制远远不止23位,会发生截断,只取23位,这也就是为什么浮点型存储会有精度损失。
而精度损失造成的后果可能会变大也可能会变小,因为在存储截断也可能会发生四舍五入进位。
两个浮点数的比较
因为精度损失,两个浮点数也就不能用==来进行比较,再举个例子:
于是在比较两个浮点数时我们要自行设置精度或者使用c语言自己定义的最小精度。
fabs是取一个数据的绝对值,而DBL_EPSILON是double类型的最小精度。
fabs的头文件是math.h,DBL_EPSILON的头文件是float.h。
至于为何要取绝对值,看下图:
两个相近浮点数相减的值在有效范围内,那么可以判定两个数相等。
浮点数与0的比较
知道了两个浮点数的比较后,我们自然就相知道浮点数与0的比较咯。
而通过类比推理只要一个浮点数减去0再与最小精度相比就能判定是否等于0。
而一个数减去0,就相当于它本身因此:
总结
本文分享到此结束了,如果对你有帮助记得一键三连哦!!!