How to detect double precision floating point overflow and underflow?
我有以下变量:
1 2 | double dblVar1; double dblVar2; |
它们可能具有较大的值,但小于最大
我对上述变量有各种算法,例如加法,乘法和幂:
1 2 3 | double dblVar3 = dblVar1 * dblVar2; double dblVar4 = dblVar1 + dblVar2; double dblVar5 = pow(dblVar1, 2); |
在以上所有内容中,我必须检查上溢和下溢。 如何在C ++中实现呢?
在很大程度上取决于上下文。要完全便携,您必须
操作前检查,例如(用于添加):
1 2 3 4 | if ( (a < 0.0) == (b < 0.0) && std::abs( b ) > std::numeric_limits<double>::max() - std::abs( a ) ) { // Addition would overflow... } |
四个基本运算符可以使用类似的逻辑。
如果您定位的所有计算机都支持IEEE(即
如果您不必考虑大型机的话,您可能会遇到这种情况
可以进行操作,然后在
结果。
对于下溢,第一个问题是是否逐步下溢
是否计入下溢。如果没有,那么只需检查是否
结果为零,
检测逐渐下溢(可能仅在以下情况下存在)
如果您有IEEE),则可以使用
如果结果对应于逐渐下溢,则返回false。
(与溢出不同,您需要在操作后测试下溢。)
POSIX,C99,C ++ 11具有
1 2 3 4 5 | int feclearexcept(int); int fegetexceptflag(fexcept_t *, int); int feraiseexcept(int); int fesetexceptflag(const fexcept_t *, int); int fetestexcept(int); |
该标志是一个位域,定义了以下位:
1 2 3 4 5 | FE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOW |
因此,您可以在操作之前清除它们,然后在进行测试。您必须检查文档,了解库函数对其的影响。
ISO C99定义了查询和操作浮点状态字的功能。您可以在方便时使用这些函数检查未捕获的异常,而不必在计算过程中担心它们。
它提供
1 2 3 4 5 | FE_INEXACT FE_DIVBYZERO FE_UNDERFLOW FE_OVERFLOW FE_INVALID |
例如
1 2 3 4 5 6 7 8 9 10 | { double f; int raised; feclearexcept (FE_ALL_EXCEPT); f = compute (); raised = fetestexcept (FE_OVERFLOW | FE_INVALID); if (raised & FE_OVERFLOW) { /* ... */ } if (raised & FE_INVALID) { /* ... */ } /* ... */ } |
http://www.gnu.org/software/libc/manual/html_node/Status-bit-operations.html
通过一个不错的编译器(它支持最新的C ++标准),您可以使用以下功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <cfenv> #include <iostream> int main() { std::feclearexcept(FE_OVERFLOW); std::feclearexcept(FE_UNDERFLOW); double overflowing_var = 1000; double underflowing_var = 0.01; std::cout <<"Overflow flag before:" << (bool)std::fetestexcept(FE_OVERFLOW) << std::endl; std::cout <<"Underflow flag before:" << (bool)std::fetestexcept(FE_UNDERFLOW) << std::endl; for(int i = 0; i < 20; ++i) { overflowing_var *= overflowing_var; underflowing_var *= underflowing_var; } std::cout <<"Overflow flag after:" << (bool)std::fetestexcept(FE_OVERFLOW) << std::endl; std::cout <<"Underflow flag after:" << (bool)std::fetestexcept(FE_UNDERFLOW) << std::endl; } /** Output: Overflow flag before: 0 Underflow flag before: 0 Overflow flag after: 1 Underflow flag after: 1 */ |