前些天刷题的时候,碰到了关于浮点数比较的一些细节问题,所以我重温了一下算法笔记中的相关介绍(2.9.2节有兴趣的同学可以自己去看一下这本书),借此写下了这篇博客
浮点数的比较
由于计算机中采用有限位的二进制编码,因此浮点数在计算机中的存储并不总是精确的。例如:在经过大量计算后,一个浮点型的数3.14在计算机中就可能存储成3.140000000.1,或者3.1399999999,等等,这种情况下会对比较操作造成极大的干扰,== 就不对了(在C/C++中“==”要完全相同才是true)。所以我们需要引入一个极小的数eps来对这种误差进行修正。
1. 等于(==)
等于区间示意图
只要a落在了[b-eps, b+eps]这个区间之间,就可以判断a与b相等(即a==b成立);
根据经验,eps取10^-8是一个合适的数字,对于大多数情况既不会漏判也不会误判;
cosnt double eps = 1e-8;
- 用宏定义来写比较操作
#define Equ(a, b) ((fabs((a)-(b))) < (eps))
- 如上,将a与b相减,若差的绝对值小于极小量eps,则返回true;
- 加上这么多的括号,是为了防止宏定义可能带来的错误;
- 想使用不等于,直接在Equ函数前加一个! 即可;
2. 大于(>)
大于区间示意图
如果a要大于b,那么就必须在误差eps的波动范围之外大于b,因此只有大于b+eps的数才能判定为
大于b(即a减b大于eps)
- 用宏定义来写大于函数如下:
#define More(a, b) (((a)-(b)) > (eps))
3. 小于(<)
小于区间示意图
如果a要小于b,那么就必须在误差eps的波动范围之外小于b,即只有小于b-eps的数才可以判定为
小于b(即a减b小于-eps)
- 用宏定义描述函数如下:
#define Less(a, b) (((a) - (b)) < (-eps))
4. 大于等于(>=)
大于等于区间示意图
可以将大于等于运算符,理解为大于和等于的结合,所以要判定a大于等于b,就要让a在误差波动范
围内能判定其大于或者等于b,即大于b-eps的数都可以判定为大于等于b
- 用宏定义表示函数如下:
#define MoreEqu(a, b) (((a) - (b)) > (-eps))
5. 小于等于(<=)
小于等于区间示意图
与大于等于同理,考虑误差波动范围,小于b + eps的数都可以判定为小于等于b
- 用宏定义表示函数如下:
#define LessEqu(a, b) (((a) - (b)) < (eps))
6. 附加一个圆周率π
const double Pi = acos(-1.0); // 因为cos(π) = -1;
- 坑:还有一些细节,后续会再补充