目录
前言:
“这还不简单啊,直接用if (float == 0)不就完事了吗?”
在我学习C语言的时候,老师突然问‘怎么判断一个浮点数是0?’我脑海里想的就是上面那个答案。
但,实事可不是这样的。因为计算机在保存浮点数的时候会有误差,不能很好的保存浮点数。所以上面的想法是错误的,那么计算机是怎么存储浮点数的呢?
一、计算机是怎么存储浮点数?
计算机底层存储整数时,是以补码形式保存数据的。补码可参考:位运算符(C语言)_憨了吧唧的人于八的博客-CSDN博客
浮点数是采用科学计数法的方式来表示的,如3.1415926
3.1415926 = 3.1415926 * 10^0
3.1415926 = 31.415926 * 10^-1
3.1415926 = 314.15926 * 10^-2
3.1415926 = 3141.5926 * 10^-3
...
对于二进制,要使用科学计数法,只需将基数10换位2
它的格式如下:
V = (-1)^S * M * R^E
每个变量含有如下:
- S:符号位,取值 0 或 1,决定一个数字的符号,0 表示正,1 表示负;
- M:底数(尾数),用小数表示,如上述例子中的3.1415926;
- R:基数,表示十进制数 R 就是 10,表示二进制数 R 就是 2;
- E:指数,用整数表示,如上述例子中10 ^ 0,中的0。
现在,如果要在计算机上保存浮点数,则只需要保存以上三个变量即可。
float:
一般为4字节,也就是32bite。
R32-24(规则):1(符号位S)+28(指数E)+23(底数M) S-(E+127)-M
double:
一般为8字节,也就是64bite。
R64-53(规则):1(符号位S)+11(指数E)+52(底数M) N-(R+1023)-M
特殊值:
无穷 : 指数全为1,底数全为0
NaN(not a number) : 指数全为1,底数不全为0
那上述E、M位是否可以改变呢?
那当然是可以的
当然指数和尾数分配的位数不同,产生的结果也不同:
- 指数位越多,底数位则越少,其表示的范围越大,但精度就会变差,反之,指数位越少,底数位则越多,表示的范围越小,但精度就会变好
- 一个数字的浮点数格式,会因为定义的规则不同,得到的结果也不同,表示的范围和精度也有差异
早期,浮点数的位数是由计算机厂商自己决定的。这样会导致,在不同浮点数规则下,程序在操作浮点数时,需要转换浮点数规则。这使程序移植性变差、开发成本升高等。为解决这一问题IEEE 组织推出了浮点数标准,这个标准统一了浮点数的表示形式,并提供了 2 种浮点格式,R32-24和R64-53。 float,double分别遵循R32-24,R64-53的标准。
而这种标准会使float的精度误差在1e-6;double精度误差在1e-15。
二、判断浮点数是否为0
我们已经知道了float精度误差在1e-6,也就是说只要浮点数的绝对值小于1e-6,就可认为是0
这里就需要知道一个函数啦:
fabs():求浮点数绝对值;
拓展:abs():求整数的绝对值。
使用以上两个函数需要先引入头文件
#include <math.h>
代码:
#include <stdio.h>
#include <math.h>
void main()
{
float a = 0;
if (fabs(a)< 1e-6)
{
printf("a 等于 0\n");
}
else
{
printf("a 不等于 0\n");
}
return;
}
双精度同理
#include <stdio.h>
#include <math.h>
void main()
{
double a = 0;
if (fabs(a)< 1e-15)
{
printf("a 等于 0\n");
}
else
{
printf("a 不等于 0\n");
}
return;
}