在一些C/C++语言的基础知识考查中,经常会遇到类似这样一个问题,给定两个浮点数,如何来判断它们是否相等?
今天就跟大家探讨一下这个问题,并通过程序试验结果来分析该问题的正确处理方法。
我们知道,在C语言中可以使用比较操作符(==)来比较两个数字是否相等,比如对于两个整数a和b,可以使用if(a==b)来判断,比如下面这段程序:
从程序以及运行结果我们可以清楚的看到,对于整数,比较操作符可以正确的给出比较结果。那么如果a和b变为浮点数,还可以这样使用吗?
让我们通过程序及其运行结果来分析,先看一下a和b相等的情况:
通过运行结果可以看到当a、b相等时,比较操作符能得到正确的结果。
下面让我们再看一看a、b不相等,但是值很接近的情况,程序及运行结果如下:
在这个小程序中,因为c=a + b,而a、b又都不为0,所以从数学意义上来说,a和c并不相等,但是程序的运行结果却告诉我们a、b相等。为什么会这样呢?让我们将a、b的值以高精度方式输出,来看看有什么奥秘,请看下面程序及其运行结果:
可见,虽然a和c在数学上不相等,但是它们在计算机中的存储内存却相等,所以导致计算机在比较时做出了相等的结果。
为了进一步说明这个问题,让我们看看数字在计算机中的存储方式。我们知道计算机是以二进制方式来保存数据内容的,整数因为可以精确的转换为一个二进制数,所以可以准确的保存内容,但是小数却不能使用这样的方式。为了在计算机中保存小数,人们发明了浮点数,这种表示法是以适当的形式将比例因子表示在数据中,让小数点的位置根据需要而浮动,类似于数学中的科学计数法。这样,在位数有限的情况下,既扩大了数字的表示范围,又保持了有效精度。
浮点数主要由三部分组成,即符号、阶码与尾数,见下图是32位和64位浮点数的组成:
浮点数的具体存储格式,以及如何将一个小数转换为二进制浮点数,可参考下面的标准。
- 二进制浮点数算术标准(IEEE Std 754-1985),也称之为IEC 50599:1989,后来该标准被ISO收录,所以又称之为IOS/IEC/IEEE 60559:2011。
- 与基数无关的浮点数算术标准(IEEE Std 854-1987)。
更多关于浮点数存储与运算的内容,已经超出了本文讨论的范围,感兴趣者可以参考相关标准的官方文档。
知道了浮点数存在精度的问题,所以上面的程序出现不正确的结果也就不足为奇了,那么回到本文开始时的问题,我们该如何来比较两个浮点数呢?只能使用近似相等,即根据程序的实际情况,定义一个精度值,当两个浮点数之差的绝对值小于该值时,即可认为它们相等,对于不等也可以使用类似的方法。
不过这里又引出一个问题,虽然用户可以定义一个精度值,那么如果为了提高精度,可以让该值无限小吗?显然也不可能,那么最小的精度是多少呢?其实为了方便浮点数的相关运算,标准库提供了一个float.h文件,并定义了一些辅助宏,比如用宏FLT_EPSILON表示单精度浮点数最高精度,以及表示双精度浮点数的宏DBL_EPSILON。
最后,给出一个规范的比较浮点数比较的函数。
由于本人水平有限,文中如果有不足之处,欢迎大家指正。