浮点数精度陷阱:为何3.14不等于3.14?
2026/9/14 23:10:56 网站建设 项目流程

计算机中的小数表示方式

计算机是这样用二进制表示一个小数的(float为例):

  • S表示一个小数的正负,M表示尾数,e表示指数,但是实际存放e的时候会对其加127(也就是E),而e的范围是【-126,127】,所以E的范围就是【1,254】(0和255表示特殊的值)。
  • 其中因为尾数表示的是小数,所以尾数的最低位的权重是2^-1,次低位权重是2^-2... .... 以此类推。
  • 另外我们可以发现如果十进制的整数部分位数越多,那么转换成1.M后其在M中占比也就越多,那么真正的十进制小数可以占尾数的比重就越少,精度也会越低

现在有一个小数3.62,我们来把它转化成float类型的计算机存储方式:

5.62 就是整数3+小数0.62 3的二进制是101 纯小数的二进制是这样计算的:首先纯小数的二进制权重是-1,-2,-3这些, 而不是0,1,2,3...那么0.62一定等于或者近似等于(2^-23*x1+2^-22*x2+...+2^-1*x23) ,如果我们对其不断乘2,那么最低位,次低位...的权重依此都会变成1, 最终只剩下x23,x22,x21...x1。所以对于0.62我们进行以下变换: 0.62*2 = 1.24 -----1 0.24*2 = 0.48 -----0 0.48*2 = 0.96 -----0 0.96*2 = 1.92 -----1 0.92*2 = 1.84 -----1 ... ... 最终我们会发现这是一个无限小数,但我们只能记录23,这就是计算机不能存储精准浮点 数的原因所在,总之,最后我们得出0.62的二进制是:10011110101110000101001 所以3.62用二进制表示就是101.10011110101110000101001 转换成科学计数法就是1.0110011110101110000101001 * 2^2 对应的0110011110101110000101001是M,2是e(E就是2+127 = 129),s就是0 然后按顺序放在float变量就好了

而读取一个数就是相反的过程。

另外我们可以谈谈为什么E的范围不包括0和255,因为他两表示一种特殊值。想必读者已经发现了,表示浮点数的时候一定要把它转换成1.M,因此可表示的浮点数的最小值就是1*2^(-126)。如果E为0,那么小数的表示就变成了:

这样浮点数的最小值就可以是0.00...01*2^(-126),所以E为0是用来降低下限,降低浮点数可以存储的最小值,这叫做非规格化,而之前的1.M叫做规格化。

E为255表示正无穷,也就是最大值


计算机中的小数比较

从上面的描述中,我们可以得知,小数的计算机表示不一定是精确的,而是可能会有偏差,因此两个浮点数比较不能直接用‘==’,当然,如果你直接比较类型相同的浮点数:

float f = 3.14; if(f == 3.14f)

这样是可以的,因为f和3.14f不论是否有偏差,他们的存储方式一定是相同的,但是你如果这样:

float f = 3.14 if(f == 3.14)

这是不可以的,3.14默认是double类型,float和double两种类型的存储精度不一样,那么就可能会不相同,除此之外,这样也是不对的:

float f = 3.14f+2.1f if(f == 5.34f)

在计算过程中,f的存储方式可能和5.34f不一样,就会导致原本应该相等最后却不相等的结果。

所以,浮点数的比较应该是带着我们所能容忍的误差的:

float f = 3.14; //判断f是不是等于3.14 if(abs(f-3.14f)<=1e-6) //1e-6是我们能容忍的最大误差

当然,上面的叫做绝对误差,而如果比较的数太小,比如比较0.000001是不是等于0.000002,虽然他们的差等于1e-6,但是这两个数相差了2倍!不应该相等。相对误差就没有这个问题:

float f = 3.14 float g = 3.1f+0.04f //表示如果两个数的比值之差低于百万分之一就算做相等 if(abs(f-g)/max(abs(f),abs(g)) < 1e-6)

但是这种方法有一个弊端,分母一但为0,任何误差都会被放大无数倍,直接被判不等,另外,当分母接近0,他们的差虽然非常非常小,但由于两个值比较接近所以比值较大,导致被判不等。我们的最终解决方案是混合误差:

float f = 3.14 float g = 3.1f+0.04f if(fabs(f-g)< max(fabs(f),fabs(g))*1e-6 || fabs(f-g)<1e-30)

相对误差用来判断大多数情况,绝对误差用来兜底,并且用乘法代替除法防止除0异常

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询