2013-03-27 8 views
16

devo seguenti variabili:Come rilevare overflow e underflow in virgola mobile a doppia precisione?

double dblVar1; 
double dblVar2; 

Essi possono avere valori grandi, ma meno di double max.

ho vari aritmetica sulle variabili di cui sopra come addizione, moltiplicazione e potenza:

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

In tutti sopra devo controllare di overflow e underflow. Come posso ottenere questo in C++?

+0

vuoi scoprire quale valore causerebbe un overflow? – 4pie0

+0

@ cf16 Sto cercando codice di esempio su come controllare overflow e underflow su operatoin arthimetic su double. – venkysmarty

+0

Verifica i valori di +/- Inf –

risposta

10

Molto dipende dal contesto. Per essere perfettamente portatile, è necessario controllare prima dell' l'operazione, ad es. (per aggiunta):

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

La logica simile può essere utilizzata per i quattro operatori di base.

Se tutte le macchine che si target supportano IEEE (che è probabilmente il caso, se non si dispone di considerare mainframe), si può solo fare le operazioni, quindi utilizzare isfinite o isinf sui risultati.

Per underflow, la prima domanda è se un underflow graduale conta come underflow oppure no. In caso contrario, è sufficiente verificare se i risultati sono zero e a != -b farebbe il trucco. Se si desidera per rilevare un underflow graduale (che probabilmente è presente solo se si dispone di IEEE), allora è possibile utilizzare isnormal — questo sarà return false se i risultati corrispondono a un underflow graduale. (A differenza di troppo pieno, si prova per underflow dopo l'operazione.)

+0

@ James cosa succede se a> 0.0 e b> 0.0 come controlliamo l'overflow qui – venkysmarty

+0

@venkysmarty Con l'espressione che ho postato. Funziona per tutti i casi (per aggiunta). –

+0

'isnormal (5.0 - 5.0)' è falso, facendo apparire come se ci fosse un underflow nella sottrazione. Non sono sicuro se l'OP vuole che questa sottrazione sia indicata come underflow (in realtà, non sono sicuro di cosa significhi l'OP "controllando [per] underflow"). –

9

POSIX, C99, C++ 11 hanno <fenv.h> (e <cfenv> per C++ 11), che hanno funzioni per testare le eccezioni IEEE754 bandiere (che non hanno nulla a che fare con eccezioni C++, sarebbe troppo facile):

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

La bandiera è un campo di bit con i seguenti bit definiti:

FE_DIVBYZERO 
FE_INEXACT 
FE_INVALID 
FE_OVERFLOW 
FE_UNDERFLOW 

in modo da poter cancellare ° em prima delle operazioni e poi testarle dopo. Dovrai controllare la documentazione per l'effetto delle funzioni della libreria su di loro.

+0

Le macro che specificano i campi di bit sono supportate solo condizionalmente; non tutti i sistemi li avranno. (E non riesco a trovare nello standard dove specifica il significato di 'FF_UNDERFLOW'. In IEEE, include underflow graduale o no?) –

+0

@JamesKanze IEEE-754 supporta valori non normalizzati (cioè underflow graduale). –

+0

@JamesKanze, è definito in IEEE 754. Dalla memoria, consente all'implementazione di scegliere tra diverse semantiche, ma ISTR che per tutte loro FE_UNDERFLOW viene generato durante la generazione di denormali se il risultato non è esatto (se non mi sbaglio , la clemenza riguarda il rilevamento della situazione prima o dopo l'arrotondamento). – AProgrammer

4

ISO C99 definisce le funzioni per interrogare e manipolare la parola di stato a virgola mobile. È possibile utilizzare queste funzioni per verificare le eccezioni non collegate quando è conveniente, piuttosto che preoccuparsi di esse nel mezzo di un calcolo.

Fornisce

FE_INEXACT 
FE_DIVBYZERO 
FE_UNDERFLOW 
FE_OVERFLOW 
FE_INVALID 

Per esempio

{ 
     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

5

Con un compilatore decente (che supporta il nuovo standard C++), è possibile utilizzare these funzioni:

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

@ ulidtko sopra il codice non viene compilato su VS2008 poiché sto ottenendo non è possibile aprire l'errore del file cfenv. Come posso superare questa situazione. Grazie – venkysmarty

+3

@venkysmarty puoi risolvere questo problema aggiornando il tuo compilatore. – ulidtko

Problemi correlati