在 <math.h> 头文件中,某些函数仅针对一定范围内的数值有意义,我们称这个范围为域(domain)。例如,sqrt() 函数仅能对非负数求平方根,所以此函数的域就为非负数。
如果我们给这类函数传递一个在域范围之外的参数,函数就会产生错误,我们称这种错误为域错误(domain error)。
在 C99 标准之前,域错误的信息只能通过 <errno.h> 中的 errno 获取。当发生域错误时,程序会将 errno 的值由默认的 0 改为 EDOM。
C99 标准新增加了 6 个头文件,其中的 <fenv.h> 专门用来处理浮点数错误,域错误也可以借助其中的 fetestexcept() 函数和 FE_INVALID 宏检测出来。
有些编译器采用了较新的 C99 标准,不再设置 errno 的值了,例如 Mac OS 下的 Xcode。
当发生域错误时,某些返回值类型为浮点数的函数会将返回值设置为 NaN(Not a Number),表示这是一个“无效的数字”。还是以 sqrt() 为例,sqrt(-100) 的返回值就是 NaN。想进一步了解 NaN,请猛击《NaN(Not a Number),表示一个无效数字》。
用代码来演示域错误:
#include <stdio.h> /* printf */
#include <math.h> /* sqrt */
#include <errno.h> /* errno */
#include <fenv.h> /* FE_INVALID */
int main()
{
printf("sqrt(-100) = %f\n", sqrt(-100));
if (errno == EDOM) {
perror("errno == EDOM");
}
if (fetestexcept(FE_INVALID)) {
puts("FE_INVALID is set");
}
return 0;
}
在 VS2015 下的运行结果:
在 GCC 下的运行结果:
在 Xcode 下的运行结果: