我有以下变量:
double dblVar1;
double dblVar2;
它们可能具有较大的值但小于double
最大值
我对上述变量有各种算法,如加法,乘法和幂:
double dblVar3 = dblVar1 * dblVar2;
double dblVar4 = dblVar1 + dblVar2;
double dblVar5 = pow(dblVar1, 2);
总之,我必须检查溢出和下溢。我怎样才能在C ++中实现这一目标?
答案 0 :(得分:12)
很大程度上取决于背景。为了完全便携,你必须 在操作之前检查,例如(补充):
if ( (a < 0.0) == (b < 0.0)
&& std::abs( b ) > std::numeric_limits<double>::max() - std::abs( a ) ) {
// Addition would overflow...
}
类似的逻辑可以用于四个基本运算符。
如果您定位的所有计算机都支持IEEE(即
如果您不必考虑大型机,可能就是这种情况),你
可以执行操作,然后使用isfinite
或isinf
结果。
对于下溢,第一个问题是是否逐渐下溢
算作是否下溢。如果没有,那么只需检查是否
结果为零,a != -b
可以解决问题。如果你想
检测逐渐下溢(这可能只是存在
你有IEEE),那么你可以使用isnormal
- 这样就可以了
如果结果对应于逐渐下溢,则返回false。
(与溢出不同,您在操作后测试下溢。)
答案 1 :(得分:9)
POSIX,C99,C ++ 11有<fenv.h>
(和<cfenv>
用于C ++ 11),它具有测试IEEE754异常标志的功能(与C ++异常无关,它会太容易了):
int feclearexcept(int);
int fegetexceptflag(fexcept_t *, int);
int feraiseexcept(int);
int fesetexceptflag(const fexcept_t *, int);
int fetestexcept(int);
该标志是一个位域,定义了以下位:
FE_DIVBYZERO
FE_INEXACT
FE_INVALID
FE_OVERFLOW
FE_UNDERFLOW
所以你可以在操作之前清除它们,然后再测试它们。您必须查看文档以了解库函数对它们的影响。
答案 2 :(得分:5)
ISO C99定义了查询和操作浮点状态字的函数。您可以使用这些函数在方便时检查未捕获的异常,而不是在计算过程中担心它们。
提供
FE_INEXACT
FE_DIVBYZERO
FE_UNDERFLOW
FE_OVERFLOW
FE_INVALID
例如
{
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
答案 3 :(得分:5)
使用合适的编译器(支持最新的C ++标准),您可以使用these函数:
#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
*/