错误处理(Error Handling)

快速指南

这个库对错误的处理被拆分为两个正交的部分( 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, roundmodf 的参数不能被表示为一个整数,或是超出返回值类型的范围的时候会出现这种错误。

计算错误(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 std::domain_error

errno_on_error

设置::errnoEDOM 并返回std::numeric_limits<T>::quiet_NaN()

ignore_error

返回std::numeric_limits<T>::quiet_NaN()

user_error

返回boost::math::policies::user_domain_error: 这个函数必须由用户定义


对于 Pole Errors可采取的措施

措施

行为

throw_on_error

抛出std::domain_error异常

errno_on_error

设置::errnoEDOM 并返回 std::numeric_limits<T>::quiet_NaN()

ignore_error

返回std::numeric_limits<T>::quiet_NaN()

user_error

返回boost::math::policies::user_pole_error: 这个函数必须由用户定义


对于溢出错误( Overflow Errors )可采取的措施

措施

行为

throw_on_error

抛出std::overflow_error异常

errno_on_error

设置::errnoERANGE 并返回std::numeric_limits<T>::infinity()

ignore_error

返回std::numeric_limits<T>::infinity()

user_error

返回boost::math::policies::user_overflow_error: 这个函数必须由用户定义


对于向下溢出( Underflow Errors)可采取的措施

措施

行为

throw_on_error

抛出std::underflow_error异常

errno_on_error

设置::errnoERANGE 并返回 0

ignore_error

返回 0

user_error

返回boost::math::policies::user_underflow_error: 这个函数必须由用户定义


对于 Denorm Errors可采取的措施

措施

行为

throw_on_error

抛出std::underflow_error异常

errno_on_error

设置::errnoERANGE 并返回 denormalised value.

ignore_error

返回 denormalised value.

user_error

返回boost::math::policies::user_denorm_error: 这个函数必须由用户定义


对于舍入错误( Rounding Errors)可采取的措施

措施

行为

throw_on_error

抛出boost::math::rounding_error 异常

errno_on_error

设置::errnoERANGE 并返回一个未指定的值

ignore_error

返回一个未指定的值( unspecified value ).

user_error

返回boost::math::policies::user_rounding_error: 这个函数必须由用户定义


对于内部计算错误( Internal Evaluation Errors)可采取的措施

措施

行为

throw_on_error

抛出boost::math::evaluation_error异常

errno_on_error

设置::errnoEDOM 并返回已查找到的最接近的逼近值.

ignore_error

返回已查找到的最接近的逼近值

user_error

返回boost::math::policies::user_evaluation_error: 这个函数必须由用户定义


对于未定义结果错误( Indeterminate Result Errors)所采取的措施

措施

行为

throw_on_error

抛出std::domain_error异常

errno_on_error

设置::errnoEDOM 并返回与ignore_error相同的值.

ignore_error

返回一个依赖于发生错误的函数的缺省值.

user_error

返回boost::math::policies::user_indeterminate_result_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, roundmodf 函数使用一个没有整数表示(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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值