2010-05-05 7 views
10

Ich benutze C++ in Visual Studio Express, um zufällige Ausdrucksbäume für die Verwendung in einem genetischen Algorithmus Programmtyp zu generieren.Wie verwende ich try ... catch, um Gleitkommafehler zu fangen?

Weil sie zufällig sind, erzeugen die Bäume oft: durch Null teilen, Überlauf, Unterlauf sowie zurückkehrende "inf" und andere Zeichenfolgen. Ich kann Handler für die Streicher schreiben, aber die Literatur hat mich über die anderen verblüfft. Wenn ich es richtig verstehe, muss ich zuerst einige Flaggen setzen?

Beratung und/oder ein Hinweis auf einige Literatur wäre willkommen. Edit: Die in der Double-Variablen zurückgegebenen Werte sind 1. # INF oder -1. # IND. Ich habe mich geirrt, sie Strings zu nennen.

+0

C++ nicht jede dieser Operationen vorschreiben sollte eine Ausnahme werfen. Sie führen zu undefiniertem Verhalten. (Was kann zum Absturz führen, oder eine Ausnahme auslösen, oder nichts tun, o ...) – GManNickG

+1

Aber C99 und POSIX geben solche Dinge an und stellen eine numerische Ausnahme-Schnittstelle zur Verfügung. Es ist jedoch ein wenig unklar, ob Peter Kontrolle über die tatsächlichen Zahlen hat, wenn er Fäden statt FP-Unendlichkeiten herauszieht. – Potatoswatter

Antwort

6

Sind Sie sicher, dass Sie sie fangen wollen, anstatt sie einfach zu ignorieren? Angenommen, Sie wollen einfach nur ignorieren:

sehen: http://msdn.microsoft.com/en-us/library/c9676k6h.aspx

Für den _MCW_EM Maske, das Löschen der Maske stellt die Ausnahme, die die Hardware-Ausnahme erlaubt; Durch Einstellen der Maske wird die Ausnahme ausgeblendet.

wirst du so etwas wie dies also tun möchte:

#include <float.h> 
#pragma fenv_access (on) 

void main() 
{ 
    unsigned int fp_control_word; 
    unsigned int new_fp_control_word; 

    _controlfp_s(&fp_control_word, 0, 0); 

    // Make the new fp env same as the old one, 
    // except for the changes we're going to make 
    new_fp_control_word = fp_control_word | _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT; 
    //Update the control word with our changes 
    _controlfp_s(&fp_control_word, new_fp_control_word, _MCW_EM) 


} 

Einige der Verwirrung hier über die Verwendung des Wortes sein kann „Ausnahme“. In C++ bezieht sich das normalerweise auf das in der Sprache integrierte Ausnahmebehandlungssystem. Gleitkommaausnahmen sind insgesamt ein anderes Biest. Die Ausnahmen, die eine Standard-FPU unterstützen muss, sind alle in IEEE-754 definiert. Diese passieren innerhalb der Gleitkommaeinheit, die verschiedene Dinge tun kann, abhängig davon, wie die Kontrollflags der Gleitkommaeinheit eingerichtet sind. Normalerweise passiert eines von zwei Dingen: 1) Die Ausnahme wird ignoriert und die FPU setzt ein Flag, das anzeigt, dass ein Fehler in ihren Statusregistern aufgetreten ist. 2) Die Ausnahme wird von der FPU nicht ignoriert, stattdessen wird ein Interrupt generiert und jeder Interrupt-Handler, der für Gleitkommafehler eingerichtet wurde, wird aufgerufen.In der Regel macht das für Sie etwas Sinnvolles, indem Sie die Codezeile im Debugger unterbrechen oder eine Core-Datei generieren.

Sie können hier mehr über IEE-754 finden: http://www.openwatcom.org/ftp/devel/docs/ieee-754.pdf

Einige zusätzliche Floating-Point-Referenzen: http://docs.sun.com/source/806-3568/ncg_goldberg.html http://floating-point-gui.de/

+1

Angenommen, der Code läuft auf einem x86-Prozessor ... – dthorpe

+1

dthorpe: eigentlich gehe ich nicht davon aus, dass es auf einem x86-Prozessor läuft. Die MSDN-Dokumentation gibt explizit an, dass _controlfp_s der neue "plattformunabhängige" Weg ist, dies zu tun. Ich vermute, dass plattformunabhängig sie sich auf den CPU-Typ beziehen, da offensichtlich nicht alle x86-Betriebssysteme diese Funktion haben - solange er dies auf einer Windows-Plattform tut, sollte er in Ordnung sein. – George

+2

Beachten Sie auch, dass Bibliotheken sich über die Einstellung des Gleitkomma-Steuerworts lustig gemacht haben, wobei jede ihre Bevorzugung der anderen vorbehielt. Fast so schlimm wie Druckertreiber, die das Gebietsschema unter dem Feed eines Programms ändern ... –

-1

es nie versucht, aber durch Null teilen unter der Annahme, löst eine Ausnahme aus, könnten Sie einfach den Code in einem Try wickeln/wie diese fangen:

versuchen { // mögliche Division durch Null ... } catch (...) { // ... fängt alle Ausnahmen }

+0

Das ist falsch, weil die C++ Laufzeitumgebung hier nicht hilft. Es wird keine Ausnahme ausgelöst, außer dem, wonach der Programmierer gezielt gefragt hat. – wilhelmtell

1

die C++ Laufzeitumgebung werden Sie die geringste hier nicht helfen. Sie müssen diese Prüfungen selbst durchführen, explizit in Ihrem Code. Es sei denn, die Funktionen, die Sie aufrufen, führen diese Überprüfungen durch - in diesem Fall hängt es davon ab, wie sie sich im Falle eines Fehlers verhalten.

Lassen Sie mich erklären:

double divide(double a, double b) { 
    return a/b; // undefined if b is zero 
} 

in der Tat sein sollte

double divide(double a, double b) { 
    if(b == 0) { 
     // throw, return, flag, ... you choose how to signal the error 
    } 
    return a/b; // b can't possibly be zero here 
} 

Wenn der Code, der auf nicht Division durch Null und so ist nicht deins dann werden Sie haben zu graben tiefer zu finden, was es im Falle einer Bedrohung für einen Fehler tut. Wirf es? Eine Flagge setzen? Fragen Sie den Autor und/oder lesen Sie die Quelle.

Hier ist ein Beispiel für eine Ausnahme:

struct bad_value : public std::exception { }; 

double divide(double a, double b) { 
    if(b == 0) throw bad_value("Division by zero in divide()"); 
    return a/b; // b can't possibly be zero here 
} 

// elsewhere (possibly in a parallel universe) ... 

    try { 
     double r1 = divide(5,4); 
     double r2 = divide(5,0); 
    } catch(bad_value e) { 
     // ... 
    } 
+0

Danke. Es sieht so aus, als müsste ich meine eigenen "Würfe" umsetzen. –

8

Nach http://msdn.microsoft.com/en-us/library/aa289157%28v=vs.71%29.aspx#floapoint_topic8,
es möglich scheint C++ Ausnahmen in MSVC zu werfen

Erstellen Sie die Ausnahmen Klassen:

class float_exception : public std::exception {}; 
class fe_denormal_operand : public float_exception {}; 
class fe_divide_by_zero : public float_exception {}; 
class fe_inexact_result : public float_exception {}; 
class fe_invalid_operation : public float_exception {}; 
class fe_overflow : public float_exception {}; 
class fe_stack_check : public float_exception {}; 
class fe_underflow : public float_exception {}; 

Karte C bis FPU Ausnahmen ++ werfen strukturierte Exception-Handler

void se_fe_trans_func(unsigned int u, EXCEPTION_POINTERS* pExp) 
{ 
    switch (u) 
    { 
    case STATUS_FLOAT_DENORMAL_OPERAND: throw fe_denormal_operand(); 
    case STATUS_FLOAT_DIVIDE_BY_ZERO:  throw fe_divide_by_zero(); 
    etc... 
    }; 
} 
. . . 
_set_se_translator(se_fe_trans_func); 

verwenden, können Sie dann versuchen verwenden Fang

try 
{ 
    floating-point code that might throw divide-by-zero 
    or other floating-point exception 
} 
catch(fe_divide_by_zero) 
{ 
    cout << "fe_divide_by_zero exception detected" << endl; 
} 
catch(float_exception) 
{ 
    cout << "float_exception exception detected" << endl; 
} 
+2

Dies sollte die genehmigte Antwort sein: es entspricht der ursprünglichen Frage (akzeptiert Antwort im Grunde sagt "Sie sollten nicht stören" und zweite sagt "Sie können nicht" (was falsch ist). – Deimos