How to detect double precision floating point overflow and underflow?

匿名 (未验证) 提交于 2019-12-03 02:08:02

问题:

I have following variables:

double dblVar1; double dblVar2; 

They may have big values but less than double max.

I have various arithmetic on above variables like addition, multiplication and power:

double dblVar3 = dblVar1 * dblVar2;  double dblVar4 = dblVar1 + dblVar2; double dblVar5 = pow(dblVar1, 2); 

In all above I have to check overflow and underflow. How can I achieve this in C++?

回答1:

A lot depends on context. To be perfectly portable, you have to check before the operation, e.g. (for addition):

if ( (a < 0.0) == (b < 0.0)     && std::abs( b ) > std::numeric_limits<double>::max() - std::abs( a ) ) {     //  Addition would overflow... } 

Similar logic can be used for the four basic operators.

If all of the machines you target support IEEE (which is probably the case if you don't have to consider mainframes), you can just do the operations, then use isfinite or isinf on the results.

For underflow, the first question is whether a gradual underflow counts as underflow or not. If not, then simply checking if the results are zero and a != -b would do the trick. If you want to detect gradual underflow (which is probably only present if you have IEEE), then you can use isnormal—this will return false if the results correspond to gradual underflow. (Unlike overflow, you test for underflow after the operation.)



回答2:

POSIX, C99, C++11 have <fenv.h> (and <cfenv> for C++11) which have functions to test the IEEE754 exceptions flags (which have nothing to do with C++ exceptions, it would be too easy):

int  feclearexcept(int); int  fegetexceptflag(fexcept_t *, int); int  feraiseexcept(int); int  fesetexceptflag(const fexcept_t *, int); int  fetestexcept(int); 

The flag is a bitfield with the following bits defined:

FE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOW 

So you can clear them before the operations and then test them after. You'll have to check the documentation for the effect of library functions on them.



回答3:

With a decent compiler (which supports the newest C++ standard), you can use these functions:

#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  */ 


回答4:

ISO C99 defines functions to query and manipulate the floating-point status word. You can use these functions to check for untrapped exceptions when it's convenient, rather than worrying about them in the middle of a calculation.

It provides

FE_INEXACT FE_DIVBYZERO FE_UNDERFLOW FE_OVERFLOW FE_INVALID 

For example

   {        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



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!