如何判断两个浮点数的值是否相等

最近温习了浮点数相关的知识。打算总结一下浮点数的概念及其本质。但是要详细地写下浮点数的方方面面得花不少时间,加之最近事儿挺多的,所以打算先写“如何判断两个浮点数的值是否相等”,等到周末再写“探究浮点数的本质”。算是抛吾之砖引吾之玉吧-_-. 为什么要单独介绍如何判断两个浮点数的值是否相等呢?简单来说,就是因为一个浮点数表示的值并不是精确的,其有一定的误差(计算机没有保存实数每一位的能力,可以认为这个能力和其占用的内存大小成正比),所以两个浮点数之间比较相等只能采用近似相等的判断方法。注意,我说的是两个浮点数之间相等只能采用近似相等,判断两个确定的浮点数变量相等可以准确判断的(当其占用内存的每一位都相同时,值肯定也相等),但是这种准确的判断一般没什么意义,也不是我们想要的,因为出现最多的情况就是计算了浮点数的表达式,然后比较表达式和其他浮点数的值。比如下文会说到的1.2/0.4和3,作为浮点数变量存储的话,它们在计算机中占用的内存的每一位不相等,对于计算机来说它们确实不等,但是这对于我们人类来说就是误差。 在C语言中,有float(占用4个字节)double(占用8个字节)、**long double(占用10个字节或16个字节)**这三种浮点数类型。它们仨实质上是一样的,只是表示的精度不同而已。我以double为例,介绍如何判断两个浮点数的值是否相等。先看一个例子:

#include <stdio.h>
int main() {
    if (1.2 / 0.4 - 3 == 0) {
        printf("1.2/0.4 equal to 3\n");
    } else {
        printf("1.2/0.4 not equal to 3\n");
    }         
    return 0;
}

上述代码应该打印什么呢?你可以执行上述代码并观察输出结果。在绝大多数机器上执行此代码,都会得到打印结果: 1.2/0.4 not equal to 3 什么!1.2除以0.4还不等于3啦,这个计算机的数学是它的体育老师教的吗?别急,从数学上来说,1.2除以0.4是一个有理数理应能准确表示,但是在计算机系统中表示一个浮点数是有其精度范围的(double类型的浮点数最多能精确表示15~17位)。在我的机器上,1.2/0.4的结果实际上是: 2.9999999999999996 2.9999999999999996当然就不等与3了,这就是为什么1.2/0.4不等于3。 现在对上述代码进行改进:

#include <stdio.h>
#include <math.h>

#define EPSILON 1.0E-13
int main() {
    if (fabs(1.2 / 0.4 - 3) < EPSILON) {
        printf("1.2/0.4 equal to 3\n");
    } else {
        printf("1.2/0.4 not equal to 3\n");
    }         
    return 0;
}

此代码就会打印: 1.2/0.4 equal to 3 宏定义#define EPSILON 1.0E-13,将EPSILON定义为极小的一个值。1.0E-13实际上就是: $$ 1.0\times10^{-13} $$ 1.0表示系数,E(exponent)表示指数,-13是指数的值,以10为底。1.0E-13用十进制表示就是: 0.0000000000001 **fabs()**是math.h中声明的一个函数,作用是获得1.2/0.4 - 3的绝对值。 上文提到,浮点数是有误差的,那么可以采用近似相等的方法来判断两个浮点数是否相等。我这里采用的方法就是,让两个浮点数的差的绝对值和极小值进行比较,如果小于极小值就认为两个浮点数是相等的,否则就不等。当然,这个极小值EPSILON可以根据你自己需求的精度来定制。