prev up next   top/contents search

comp.lang.c FAQ 列表· 第 14.5 题

Q什么是检查浮点数“足够接近”的有效方法?


A由于浮点数值的绝对精度按其定义与其量级有关,因此比较两个浮点数值的最佳方法是使用相对于被比较数字量级的精度阈值。而不是

	double a, b;
	...
	if(a == b)	/* WRONG */
使用类似
	#include <math.h>

	if(fabs(a - b) <= epsilon * fabs(a))
其中epsilon是一个用于设定“接近度”的阈值(并且您知道a不为零)。精确值epsilon可能仍需谨慎选择:其适当值可能非常小,并且仅与机器的浮点精度相关,或者如果被比较的数字本质上精度较低,或者它们是经过一系列计算(在多个步骤中累积精度损失)的结果,则可能较大。(此外,您可能需要将阈值设为函数b,或两者兼有ab.)

一种明显较差的方法,通常不推荐,是使用绝对阈值

	if(fabs(a - b) < 0.001)		/* POOR */
像 0.001 这样的绝对“模糊因子”似乎从来都不好用。随着被比较数字的变化,很可能两个本应视为不同的较小数恰好相差在 0.001 之内,或者两个本应视为相等的较大数相差大于 0.001。(当然,当模糊因子调整为 0.005、0.0001 或任何其他绝对数字时,问题只会转移,而不会消失。)

Doug Gwyn 建议使用以下“相对差值”函数。它返回两个实数的相对差值:如果它们完全相同则为 0.0,否则为差值与其中较大者之比。

#define Abs(x)    ((x) < 0 ? -(x) : (x))
#define Max(a, b) ((a) > (b) ? (a) : (b))

double RelDif(double a, double b)
{
	double c = Abs(a);
	double d = Abs(b);

	d = Max(c, d);

	return d == 0.0 ? 0.0 : Abs(a - b) / d;
}
典型用法是
	if(RelDif(a, b) <= TOLERANCE) ...

参考:Knuth 第 4.2.2 节第 217-8 页


prev up next   contents search
关于此 FAQ 列表   关于 Eskimo   搜索   反馈   版权

Eskimo North 托管