错误情况的处理
除非另有明确说明,否则对于所有输入实参的可表示值,<math.h>头文件中函数的行为都是明确规定的。每个函数都像单个操作一样执行,而不会引发SIGFPE,并且不会产生任何域异常、极点异常或者溢出范围异常,除了反映函数结果。
对于所有函数,如果实参超出函数定义范围将发生域错误(domain error)。每个函数都列出了所有必需的域错误;实现可以定义额外的域错误,只要这些错误与函数的数学定义一致;例如:如果函数的数学域不包括无穷大,而实现支持无穷大,则允许作为实参的无穷大引发域错误。发生域错误时,函数返回一个实现定义值。如果表达式math_errhandling & MATH_ERRNO为非0值,则errno值为EDOM;如果表达式math_errhandling & MATH_ERREXCEPT为非0值,将引发域异常("invalid" floating-point exception)。
因为有限实参接近极限,数学函数具有精确的无穷大结果时,会出现极点错误(pole error);例如:log(0.0)。每个函数都列出了所有必需的极点错误;实现可以定义额外的极点错误,只要这些错误与函数的数学定义一致。发生极点错误时,函数返回一个实现定义值。如果表达式math_errhandling & MATH_ERRNO为非0值,则errno值为ERANGE;如果表达式math_errhandling & MATH_ERREXCEPT为非0值,将引发极点异常("divide-by-zero" floaing-point exception)。
当函数的数学结果由于极端大小而无法使用指定类型的对象表示时,将发生范围错误(range error)。每个函数都列出了所有必需的范围错误;实现可以定义额外的范围错误,只要这些错误与函数的数学定义一致,并且是溢出(overflow)或者下溢(underflow)的结果。必需的范围错误应报告;实现定义的范围错误可以报告。
如果一个具有常规精度(ordinary accuracy)的有限结果值,其值(绝对值)对于指定类型的全精度表示来说过大,则浮点结果发生溢出(overflow)。结果为无穷大的情况不属于溢出。如果浮点结果溢出并且默认的舍入模式生效,函数将根据返回值类型返回HUGE_VAL、HUGE_VALF或者HUGE_VALL,返回值符号与函数的正确值相同;但对于超出溢出阈值(overflow threshold)后使用降低精度表示数值的类型,函数可能返回该类型的、精度低于全精度的结果表示。如果浮点结果溢出并且默认的舍入模式生效,并且表达式math_errhandling & MATH_ERRNO为非0值,则errno值为ERANGE;如果浮点结果溢出,并且表达式math_errhandling & MATH_ERREXCEPT为非0值,无论默认的舍入模式是否生效将引发溢出异常("overflow" floating-point exception)。
(注:常规精度由实现决定,是结果不受极端值影响时的函数精度。)
如果一个具有常规精度的非0结果值,其值(绝对值)小于指定类型的最小规格化数(the minimum normalized number),浮点结果会发生下溢(underflow)。此外具有常规精度并且值达到最小规格化数的结果也可能发生下溢;但明确规定为精确0的0结果不会视为下溢。如果发生下溢,函数将返回一个实现定义值,其绝对值不大于对应浮点类型的最小正规格化数(the smallest normalized positive number)。如果表达式math_errhandling & MATH_ERRNO为非0值,errno值是否为ERANGE将由实现定义;如果表达式math_errhandling & MATH_ERREXCEPT为非0值,是否引发下溢异常("underflow" floating-point exception)将由实现定义。
(注:这里的术语下溢同时包含ISO/IEC 60559标准中的渐进式下溢(gradual underflow)和突变为0式下溢(flush-to-zero underflow)。渐进式下溢采用次规格化数来逐渐逼近0,能够保持精度但性能较低。突变为0式下溢是结果直接变为0,性能较高但损失精度。根据ISO/IEC 60559标准,下溢可能发生这种情况:舍入后的结果值(保持该类型的完整精度。)等于该格式中的最小规格化数。)
如果发生域错误、极点错误或者范围错误,并且表达式math_errhandling & MATH_ERRNO为0(这种情况下,数学错误使用浮点异常标记(floating-point exception flags),而不使用errno。),errno应设置成对应的错误值,或者保持不变。如果没有发生域错误、极点错误或者范围错误,errno应保持不变;这种情况下errno值与math_errhandling的设置无关。
主要参考资料: