¿Cómo detectar desbordamiento y subdesbordamiento de coma flotante de doble precisión?

Tengo las siguientes variables:

double dblVar1; double dblVar2; 

Pueden tener grandes valores pero menos del double máximo.

Tengo varias aritméticas en variables anteriores como sum, multiplicación y potencia:

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

En todo lo anterior, tengo que verificar el desbordamiento y el flujo inferior. ¿Cómo puedo lograr esto en C ++?

Mucho depende del contexto. Para ser perfectamente portátil, debe verificar antes de la operación, por ejemplo (para la adición):

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

Se puede usar una lógica similar para los cuatro operadores básicos.

Si todas las máquinas a las que apunta son compatibles con IEEE (que probablemente sea el caso si no tiene que considerar mainframes), puede simplemente hacer las operaciones, luego usar isfinite o isinf en los resultados.

Para subdesbordamiento, la primera pregunta es si un subdesbordamiento gradual cuenta como subdesbordamiento o no. Si no, simplemente verificando si los resultados son cero y a != -b haría el truco. Si desea detectar subdesbordamiento gradual (que probablemente solo esté presente si tiene IEEE), entonces puede usar isnormal ; esto arrojará falso si los resultados corresponden a subdesbordamiento gradual. (A diferencia del desbordamiento, prueba el underflow después de la operación).

POSIX, C99, C ++ 11 tienen (y para C ++ 11) que tienen funciones para probar los indicadores de excepciones IEEE754 (que no tienen nada que ver con las excepciones de C ++, sería demasiado fácil) :

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

La bandera es un campo de bits con los siguientes bits definidos:

 FE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOW 

Entonces puede borrarlos antes de las operaciones y luego probarlos después. Deberá verificar la documentación sobre el efecto de las funciones de la biblioteca en ellos.

Con un comstackdor decente (que admite el último estándar de C ++), puede usar estas funciones:

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

ISO C99 define funciones para consultar y manipular la palabra de estado de coma flotante. Puede usar estas funciones para buscar excepciones no atrapadas cuando sea conveniente, en lugar de preocuparse por ellas en medio de un cálculo.

Proporciona

 FE_INEXACT FE_DIVBYZERO FE_UNDERFLOW FE_OVERFLOW FE_INVALID 

Por ejemplo

  { 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