2010-02-08 21 views
10

Non sono sicuro di come gestire le eccezioni in virgola mobile in C o C++. Da wiki, ci sono i seguenti tipi di floating point eccezioni:Gestione delle eccezioni a virgola mobile

IEEE 754 specifies five arithmetic errors that are to be recorded in "sticky bits" (by default; note that trapping and other alternatives are optional and, if provided, non-default). 

* inexact, set if the rounded (and returned) value is different from the mathematically exact result of the operation. 
* underflow, set if the rounded value is tiny (as specified in IEEE 754) and inexact (or maybe limited to if it has denormalisation loss, as per the 1984 version of IEEE 754), returning a subnormal value (including the zeroes). 
* overflow, set if the absolute value of the rounded value is too large to be represented (an infinity or maximal finite value is returned, depending on which rounding is used). 
* divide-by-zero, set if the result is infinite given finite operands (returning an infinity, either +∞ or −∞). 
* invalid, set if a real-valued result cannot be returned (like for sqrt(−1), or 0/0), returning a quiet NaN. 

è che quando qualsiasi tipo di cui sopra eccezioni accade, il programma si chiude in modo anomalo? O il programma trasporterà questo errore senza menzionare nulla e quindi rendere l'errore difficile da eseguire il debug?

È un compilatore come gcc in grado di dare un avviso per qualche caso ovvio?

Cosa posso fare durante la codifica del mio programma per notificare dove si verifica l'errore e che tipo è quando accade, in modo che possa individuare facilmente l'errore nel mio codice? Si prega di fornire soluzioni in entrambi i casi C e C++.

Grazie e saluti!

+0

risposte saranno probabilmente specifiche per un sistema operativo. Ne hai uno in mente? –

+0

Sia linux che windows, anche se ora sto usando Linux più spesso. – Tim

+0

Non vedo come la semantica in virgola mobile definita da ISO/IEEE sarà dipendente dal sistema operativo. – Jeff

risposta

6

Su Linux è possibile utilizzare l'estensione GNU feenableexcept (nascosta nella parte inferiore della pagina) per attivare il trapping sulle eccezioni in virgola mobile: se si esegue questa operazione, si riceverà il segnale SIGFPE quando si verifica un'eccezione può quindi catturare il tuo debugger. Attenzione perché a volte il segnale viene lanciato sull'istruzione in virgola mobile dopo il quello che sta effettivamente causando il problema, fornendo informazioni di riga fuorvianti nel debugger!

+0

Grazie, Mike! se senza chiamare feenableexcept, è impossibile per SIGFPE essere trappola? Se si utilizza solo la libreria standard C per specificare un gestore per SIGFPE tramite signal() senza chiamare feenableexcept nell'estensione GNU, il mio programma riceverà SIGFPE? – Tim

11

Ci sono molte opzioni, ma il generale e anche la filosofia di default introdotto da 754 è quello di non trappola ma invece di produrre risultati speciali come infiniti che possono o non possono essere rilevati dagli importanti risultati.

Di conseguenza, le funzioni che verificano lo stato delle singole operazioni non vengono utilizzate tutte le volte che le funzioni che verificano le rappresentazioni dei risultati.

Vedi, per esempio ...

LIST OF FUNCTIONS 

Each of the functions that use floating-point values are provided in sin- 
gle, double, and extended precision; the double precision prototypes are 
listed here. The man pages for the individual functions provide more 
details on their use, special cases, and prototypes for their single and 
extended precision versions. 

int fpclassify(double) 
int isfinite(double) 
int isinf(double) 
int isnan(double) 
int isnormal(double) 
int signbit(double) 

Update: Per chi pensa davvero ops FPU generano SIGFPE in un caso di default in questi giorni, vorrei incoraggiarvi a provare questo programma. È possibile generare facilmente underflow, overflow e divide per zero. Quello che non generano (a meno che non lo si esegue l'ultimo superstite VAX o un non-754 RISC) è SIGFPE:

#include <stdio.h> 
#include <stdlib.h> 
int main(int ac, char **av) { return printf("%f\n", atof(av[1])/atof(av[2])); } 
+0

Devo aggiungere che non ti importa di molti dei pezzetti appiccicosi. L'underflow è raro e circa lo stesso di zero. Inexact è troppo comune a cui preoccuparsi. – DigitalRoss

+0

Grazie! Per verificare il risultato di ogni espressione sembra troppo da gestire nel codice. Anche con i test per alcuni risultati ritenuti importanti, è comunque molto probabile che i risultati senza test generino eccezioni. Tutto ciò che spero di fare è catturare l'eccezione per segnalare dove accade e che tipo è. – Tim

+0

Non ci sarà un'eccezione e non è necessario testare dopo le operazioni. C99 ha introdotto funzioni per testare i bit appiccicosi FPU ma non sono ancora universalmente disponibili e anche se fossero non si vorrebbe perdere tempo. – DigitalRoss

2

diversi compilatori gestiscono questi errori in modi diversi.

L'inesattezza è quasi sempre il risultato della divisione di numeri con un valore assoluto maggiore di uno (forse attraverso le funzioni trancendentali). Aggiungere, sottrarre e moltiplicare i numeri con un valore assoluto> 1.0 può solo comportare un overflow.

L'underflow non si verifica molto spesso e probabilmente non sarà un problema nei calcoli normali ad eccezione delle funzioni iterate come la serie Taylor.

Overflow è un problema che può essere rilevato da una sorta di confronto "infinito", diversi compilatori variano.

Divide per zero è piuttosto notevole poiché il programma si arresta (dovrebbe) in caso di arresto anomalo se non si dispone di un gestore errori. Controllare dividendi e divisori aiuterà a evitare il problema.

Le risposte non valide di solito vengono rilevate senza gestori di errori speciali con una sorta di errore DOMAIN stampato.

[EDIT]

Questo potrebbe aiutare: (Calcolo Numerico Guida da Sun) http://docs.sun.com/source/806-3568/

0

In Linux, è possibile intercettare queste eccezioni intrappolando il segnale SIGFPE. Se non fai nulla, queste eccezioni interromperanno il tuo programma. Per impostare un gestore, usa la funzione segnale, passando il segnale che intendi intrappolare e la funzione da chiamare nel caso in cui il segnale scatti.

+0

Grazie! È possibile sapere e stampare dove si verifica l'eccezione nella funzione che gestisce il segnale? – Tim

+0

Questo non è vero. In generale, solo i sistemi pre-754 generano SIGFPE per le singole operazioni. Inoltre, cose come inesatte e underflow non sono mai state eccezioni. Questo programma può essere creato per generare x/0, overflow e underflow. Non genererà un SIGFPE.'#include #include int main (int ca, char ** av) {return printf ("% f \ n ", atof (av [1])/atof (av [2])); } ' – DigitalRoss

1

C99 ha introdotto funzioni per la gestione delle eccezioni in virgola mobile. Prima di eseguire un'operazione in virgola mobile, è possibile utilizzare feclearexcept() per cancellare eventuali eccezioni in sospeso. Dopo l'operazione/le operazioni, è possibile utilizzare fetestexcept() per verificare quali flag di eccezione sono impostati.

4

Su Windows con Visual C++, è possibile controllare quali eccezioni in virgola mobile vengono smascherate utilizzando _control87() etc.. Le eccezioni a virgola mobile non mascherate generano eccezioni strutturate, che possono essere gestite utilizzando __try/__except (e un paio di altri meccanismi). Questo è completamente dipendente dalla piattaforma.

se lasciate floating point eccezioni mascherati, un altro approccio dipendente dalla piattaforma per rilevare queste condizioni è per cancellare lo stato a virgola mobile utilizzando _clear87() etc., effettuare calcoli, e poi interrogare lo stato a virgola mobile utilizzando _status87() etc..

C'è qualcosa di meglio del suggerimento di DigitalRoss di controllare il risultato? Nella maggior parte dei casi, non lo è. Se è necessario rilevare (o controllare) l'arrotondamento (che è improbabile), allora forse?

Su Windows con Borland/CodeGear/Embarcadero C++, alcune eccezioni in virgola mobile vengono disattivate per impostazione predefinita, il che causa spesso problemi quando si utilizzano librerie di terze parti che non sono state testate con le eccezioni a virgola mobile non mascherate.