快速指南
这个库对错误的处理被拆分为两个正交的部分( orthogonal parts ):
- 产生了哪种错误?
- 当产生错误时如何处理?
可能产生的错误为:
-
定义域错误(Domain Error)
-
当函数的一个或多个参数超出范围时出现这种错误。
Pole Error
-
当特殊的参数引起函数在一个pole处(没有定义良好的剩余值(residual value))计算会出现这种错误。例如,如果函数tgamma 在-2处计算时,依据你从-2之上还是从-2之下进行逼近,这个函数会逼近不同的极限值。因此,这个函数在-2这个值处不是定义良好的(well defined),并且将会产生一个Pole Eror。
向上溢出错误(Overflow Error)
-
当结果是无限的,或者结果太大以至于不能在函数的返回值的数值类型中表示,那么将会出现这种错误。
向下错误溢出错误(Underflow Error)
-
当结果不为0,但是太小以至于不能在函数的返回值的数值类型中表示,那么将会出现这种错误。
Denormalisation Error
-
当返回值是一个denormalised value时出现这种错误。
舍入错误(Rounding Error)
-
当函数 trunc, round 和 modf 的参数不能被表示为一个整数,或是超出返回值类型的范围的时候会出现这种错误。
计算错误(Evaluation Error)
-
当出现内部错误,使得结果不能被计算的时候出现:这永远都不应当出现,但是如果出现这种错误,可能是因为迭代算法收敛得不够快。
未定义结果错误(Indeterminate Result Error)
-
当对于传递给函数的参数值,函数的结果是未定义的时候会出现这种错误。
在每种错误情况下所采取的处理方法由当前的策略 来决定。这可以用过设置一些配置宏来在工程范围(project-wide)来改变策略,或是在名字空间作用域,或是在调用点(通过为调用的函数指定一个特定的策略)改变策略。
可以采取的错误处理措施是:
-
throw_on_error
-
抛出一个最适合错误情况的异常。
errno_on_error
-
将 ::errno 设置为一个合适的值,并返回最合适的结果。
ignore_error
-
忽略这个错误并返回最合适的值。
user_error
-
调用一个用户提供的错误处理方法。
下面的表中所有的错误和采取的错误处理措施的排列(permutations),每种错误的缺省处理措施以黑体显示:
对于定义域错误( Domain Errors)可采取的措施
措施 | 行为 |
---|---|
throw_on_error | Throws |
errno_on_error | 设置 |
ignore_error | 返回 |
user_error | 返回 |
对于 Pole Errors可采取的措施
措施 | 行为 |
---|---|
throw_on_error | 抛出 |
errno_on_error | 设置 |
ignore_error | 返回 |
user_error | 返回 |
对于溢出错误( Overflow Errors )可采取的措施
措施 | 行为 |
---|---|
throw_on_error | 抛出 |
errno_on_error | 设置 |
ignore_error | 返回 |
user_error | 返回 |
对于向下溢出( Underflow Errors)可采取的措施
措施 | 行为 |
---|---|
throw_on_error | 抛出 |
errno_on_error | 设置 |
ignore_error | 返回 0 |
user_error | 返回 |
对于 Denorm Errors可采取的措施
措施 | 行为 |
---|---|
throw_on_error | 抛出 |
errno_on_error | 设置 |
ignore_error | 返回 denormalised value. |
user_error | 返回 |
对于舍入错误( Rounding Errors)可采取的措施
措施 | 行为 |
---|---|
throw_on_error | 抛出 |
errno_on_error | 设置 |
ignore_error | 返回一个未指定的值( unspecified value ). |
user_error | 返回 |
对于内部计算错误( Internal Evaluation Errors)可采取的措施
措施 | 行为 |
---|---|
throw_on_error | 抛出 |
errno_on_error | 设置 |
ignore_error | 返回已查找到的最接近的逼近值 |
user_error | 返回 |
对于未定义结果错误( Indeterminate Result Errors)所采取的措施
措施 | 行为 |
---|---|
throw_on_error | 抛出 |
errno_on_error | 设置 |
ignore_error | 返回一个依赖于发生错误的函数的缺省值. |
user_error | 返回 |
原理
当前库实现的灵活性是相当明显的,缺省行为的选择依据过去的库的复审过程中的反馈信息:
- 真正的错误(Genuine errors) 应当使用异常来标记出来而不是遵循C-兼容的行为并设置 ::errno。
- 数值向下溢出和denormalised results 在大多数情况下不被当作是严重错误(fatal errors) ,因此这些错误应当被忽略。
查找更多信息
在策略指南的改变缺省策略中有一个例子。
将一个非法参数(负的自由度)传递给一个学生t分布的的例子的完整代码在错误处理实例中。
各种错误情况在下面进行了更详细的描述。
定义域错误(Domain Errors)
当向一个特殊函数传递一个超出它所定义的变量范围的参数的时候,那么函数返回结果为:
boost::math::policies::raise_domain_error<T>(FunctionName, Message, Val, Policy);
其中T
是传递给函数的浮点类型,FunctionName
是函数的名字,Message
是描述问题的报错消息。 Val 是超出范围的值,且Policy 是当前调用的函数所使用的策略。
这些策略的缺省行为是抛出一个 std::domain_error C++ 异常。但是如果Policy 将忽略错误,并设置全局变量 ::errno,那么将返回一个 NaN 。
选择这种行为是为了与ISO/IEC 9899:1999 Programming languages - C 以及 Draft Technical Report on C++ Library Extensions, 2005-06-24, section 5.2.1, paragraph 6相兼容:
"如果一个参数的值为NaN,那么上面声明的每个函数都应当返回NaN(Not a Number),但它不应当报出定义域错误。否则,上面声明的每个函数都应当对超出定义域的参数报出定义域错误:
"这个函数说明的返回条款( Returns clause )明确地指定一个值域以及这些超出指定值域的参数;或者
"对应的数学函数的值有一个非零的虚部(imaginary component); 或者
"对应的数学函数在数学上是未定义的"
"提示 2:一个数学函数是在数学上定义的,对于一个给定的参数集合,如果这个数学参数明确针对那些参数进行了定义,或者如果它的极限值存在并且不依赖于逼近的方向 (A mathematical function is mathematically defined for a given set of argument values if it is explicitly defined for that set of argument values or if its limiting value exists and does not depend on the direction of approach)."
注意,为了在抛出异常时支持具有丰富信息的报错消息,Message
必须包含一个Boost.Format 可以解析的格式化指定符号:参数Val
对应指定符号被插入到这个报错消息中。
例如,如果Message
包含一个"%1%" ,那么它将使用T类型的完全精度的Val
值来替换,其中"%.3g" 将包含 Val
具有3个数字的值,参考Boost.Format 文档了解更多 信息。
在 pole处计算
当给一个特殊函数传递了一个在pole处而没有定义良好的剩余值(residual value)的参数值的时候,那么函数返回的结果为:
boost::math::policies::raise_pole_error<T>(FunctionName, Message, Val, Policy);
其中T
是传递给函数的浮点类型,FunctionName
是函数的名字,Message
是描述问题的报错消息。 Val 是在pole处的参数的值,且Policy 是当前调用的函数所使用的策略。
这个函数的函数行为是缺省一个std::domain_error 异常。但是可以使用错误处理策略 来改变函数的缺省策略,例如改为ignore_error
并返回 NaN。
注意,为了在抛出异常时支持具有丰富信息的报错消息,Message
必须包含一个Boost.Format 可以解析的格式化指定符号:参数Val
对应指定符号被插入到这个报错消息中。
例如,如果Message
包含一个"%1%" ,那么它将使用T类型的完全精度的Val
值来替换,其中"%.3g" 将包含 Val
具有3个数字的值,参考Boost.Format 文档了解更多 信息。
数值溢出(Numeric Overflow)
当特殊函数的结果太大以至于不能存储在参数的浮点类型中时,那么函数返回的结果为:
boost::math::policies::raise_overflow_error<T>(FunctionName, Message, Policy);
其中T
是传递给函数的浮点类型,FunctionName
是函数的名字,Message
是描述问题的报错消息,且Policy 是当前调用的函数所使用的策略。
这个函数的缺省策略的行为是抛出std::overflow_error
C++ 异常。但是如果,例如,使用了一个ignore_error
策略,那么函数返回std::numeric_limits<T>::infinity()
。在这种情况下,如果类型T不支持无限值,那么这个类型的最大值将被返回。
数值向下溢出(Numeric Underflow)
如果特殊函数的结果已知为非零,但是计算结果发生向下溢出为0,那么函数的返回的结果为:
boost::math::policies::raise_underflow_error<T>(FunctionName, Message, Policy);
其中T
是传递给函数的浮点类型,FunctionName
是函数的名字,Message
是描述问题的报错消息,且Policy 是当前调用的函数所使用的策略。
函数在缺省情况下返回0。但使用其它的策略,类似于throw_on_error
,将抛出一个std::underflow_error
C++ 异常。
Denormalisation Errors
特殊函数的计算结果是一个denormalised value z ,那么函数的返回值是:
boost::math::policies::raise_denorm_error<T>(z, FunctionName, Message, Policy);
其中T
是传递给函数的浮点类型,FunctionName
是函数的名字,Message
是描述问题的报错消息,且Policy 是当前调用的函数所使用的策略。
函数的缺省行为是返回z值。但是使用其它的策略,类似于throw_on_error
将会抛出一个std::underflow_error
C++ 异常。
计算错误(Evaluation Errors)
当一个特殊函数计算的结果已知是错误的,或者结果是不可计算的,那么函数调用:
boost::math::policies::raise_evaluation_error<T>(FunctionName, Message, Val, Policy);
其中T
是传递给函数的浮点类型,FunctionName
是函数的名字,Message
是描述问题的报错消息,Val是引发错误的值,且Policy 是当前调用的函数所使用的策略。
The default behaviour of this function is to throw a boost::math::evaluation_error
.
注意,为了在抛出异常时支持具有丰富信息的报错消息,Message
必须包含一个Boost.Format 可以解析的格式化指定符号:参数Val
对应指定符号被插入到这个报错消息中。
例如,如果Message
包含一个"%1%" ,那么它将使用T类型的完全精度的Val
值来替换,其中"%.3g" 将包含 Val
具有3个数字的值,参考Boost.Format 文档了解更多 信息。
未定义的结果错误(Indeterminate Result Errors)
当对于传递给特殊函数的参数值,特殊函数的结果是一个未定义的值时,那么返回的返回值为:
boost::math::policies::raise_overflow_error<T>(FunctionName, Message, Val, Default, Policy);
其中T
是传递给函数的浮点类型,FunctionName
是函数的名字,Message
是描述问题的报错消息,Val是未定义的值,缺省情况下是一个必须被ignore_error 和 errno_on_error策略返回的值, 且Policy 是当前调用的函数所使用的策略。
这个函数的缺省策略是ignore_error
:注意,这种错误类型为结果是数学上未定义的或是未知的值的情况保留,但是没有一个返回值应当是多少的约定(convention):例如,C99标准规定 00 为 1,尽管这个值在数学上是未知的。
舍入错误(Rounding Errors)
当 trunc, round 和 modf 函数使用一个没有整数表示(integer representation)的参数调用时调用,或者参数太大以至于不能在返回值的类型中表示出来,那么返回值的结果是对于下面函数的调用:
boost::math::policies::raise_rounding_error<T>(FunctionName, Message, Val, Policy);
其中T
是传递给函数的浮点类型,FunctionName
是函数的名字,Message
是描述问题的报错消息,Val是引发错误的参数值,且Policy 是当前调用的函数所使用的策略。
The default behaviour of this function is to throw a boost::math::rounding_error
.
注意,为了在抛出异常时支持具有丰富信息的报错消息,Message
必须包含一个Boost.Format 可以解析的格式化指定符号:参数Val
对应指定符号被插入到这个报错消息中。
例如,如果Message
包含一个"%1%" ,那么它将使用T类型的完全精度的Val
值来替换,其中"%.3g" 将包含 Val
具有3个数字的值,参考Boost.Format 文档了解更多 信息。
类型转换带来的错误(Errors from typecasts)
为了在结果中确保完全的机器精度( machine precision),许多特殊函数使用比参数精度高的类型进行计算:例如一个参数为float的函数在内部可能会使用double精确度来计算结果。上面出现的很多错误可能不会在计算的过程中出现,但在将计算结果转换为更窄的返回值类型时会出现上面的错误。这个函数
template <class T, class Policy, class U> T checked_narrowing_cast(U const& val, const char* function);