2010-02-08 19 views
10

Ich bin nicht sicher, wie mit Gleitkommaausnahmen in C oder C++ umzugehen ist. Von dem Wiki, folgen dort Arten von Punkt Ausnahmen floating:Umgang mit Gleitkommaausnahmen

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. 

Ist es, dass, wenn irgendeine Art von oben Ausnahmen geschieht, wird das Programm nicht normal beenden? Oder das Programm wird diesen Fehler auftragen, ohne etwas zu erwähnen, und macht daher den Fehler schwer zu debuggen?

Kann ein Compiler wie gcc eine Warnung für einen offensichtlichen Fall geben?

Was kann ich während der Codierung meines Programms tun, um zu benachrichtigen, wo der Fehler auftritt und welche Typen es ist, wenn es passiert, so dass ich den Fehler leicht in meinem Code finden kann? Bitte geben Sie Lösungen in C und C++ Fall.

Danke und Gruß!

+0

Antworten werden wahrscheinlich spezifisch für ein Betriebssystem sein. Hast du einen Gedanken? –

+0

Sowohl Linux als auch Windows, obwohl ich jetzt häufiger Linux benutze. – Tim

+0

Ich sehe nicht, wie ISO/IEEE-definierte Fließkomma-Semantik OS-abhängig sein wird. – Jeff

Antwort

6

Unter Linux können Sie die GNU-Erweiterung feenableexcept (unten rechts auf dieser Seite) verwenden, um Trapping bei Gleitkommaausnahmen zu aktivieren - wenn Sie dies tun, dann erhalten Sie das Signal SIGFPE, wenn eine Ausnahme auftritt, die Sie kann dann in Ihrem Debugger fangen. Achten Sie jedoch darauf, dass manchmal das Signal auf die Fließkomma-Anweisung nach geworfen wird, die das Problem verursacht und irreführende Zeileninformationen im Debugger liefert!

+0

Danke, Mike! Wenn es nicht möglich ist, feenable except zu verwenden, ist es für SIGFPE unmöglich, eine Falle zu sein? Wenn nur die C-Standardbibliothek verwendet wird, um einen Handler für SIGFPE durch signal() zu spezifizieren, ohne feenableexcept in der GNU-Erweiterung aufzurufen, wird mein Programm dann SIGFPE erhalten? – Tim

11

Es gibt viele Optionen, aber die allgemeine und auch die Standard-Philosophie von 754 eingeführt ist nicht Falle, sondern stattdessen spezielle Ergebnisse wie Unendlichkeiten zu produzieren, die in wichtigen Ergebnisse nicht angezeigt oder nicht.

Daher werden die Funktionen, die den Status der einzelnen Operationen testen, nicht so oft verwendet wie die Funktionen, die die Darstellung der Ergebnisse testen.

Siehe zum Beispiel ...

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: Für alle, die wirklich denkt FPU ops SIGFPE in einem Standardfall erzeugen in diesen Tagen, ich möchte Sie ermutigen, dieses Programm zu versuchen. Sie können leicht Unterlauf, Überlauf und Division durch Null generieren. Was Sie nicht erzeugen (wenn Sie es auf dem letzten überlebenden VAX oder einem nicht-754 RISC laufen) ist SIGFPE:

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

Ich sollte hinzufügen, dass Sie sowieso nicht viele der Sticky Bits kümmern. Unterlauf ist selten und ungefähr gleich Null. Inexakt ist zu gewöhnlich, um sich darum zu kümmern. – DigitalRoss

+0

Danke! Das Ergebnis jedes Ausdrucks zu testen, scheint im Code zu viel zu sein. Selbst wenn Tests für einige als wichtig erachtete Ergebnisse durchgeführt werden, ist es sehr wahrscheinlich, dass die Ergebnisse ohne Tests Ausnahmen ausschließen. Alles, was ich zu tun hoffe, ist, die Ausnahme zu erfassen, um zu melden, wo es passiert und um welchen Typ es sich handelt. – Tim

+0

Es wird keine Ausnahme geben und Sie müssen nach Operationen nicht testen. C99 hat Funktionen eingeführt, um die FPU Sticky Bits zu testen, aber sie sind immer noch nicht überall verfügbar und selbst wenn sie es wären, würden Sie die Zeit nicht verschwenden wollen. – DigitalRoss

2

Verschiedene Compiler diese Fehler auf unterschiedliche Weise behandeln.

Inexaktheit ist fast immer das Ergebnis der Division von Zahlen mit einem absoluten Wert größer als eins (vielleicht durch trancendentale Funktionen). Das Addieren, Subtrahieren und Multiplizieren von Zahlen mit einem absoluten Wert> 1,0 kann nur zum Überlauf führen.

Unterlauf tritt nicht sehr häufig auf und wird wahrscheinlich in normalen Berechnungen außer bei iterierten Funktionen wie Taylor-Reihen keine Rolle spielen.

Überlauf ist ein Problem, das normalerweise durch eine Art "Unendlichkeitsvergleich" erkannt werden kann, verschiedene Compiler variieren.

Divide durch Null ist ziemlich bemerkbar, da Ihr Programm abstürzen wird (sollte), wenn Sie keinen Fehlerhandler haben. Die Überprüfung von Dividenden und Divisoren hilft, das Problem zu vermeiden.

Ungültige Antworten werden in der Regel ohne spezielle Fehlerbehandlungsroutinen abgefangen, die einen DOMAIN-Fehler enthalten.

[EDIT]

Dies könnte helfen: (Numerical Computation Guide von Sun) http://docs.sun.com/source/806-3568/

0

In Linux können Sie Trap diese Ausnahmen durch die SIGFPE Signal Trapping. Wenn Sie nichts tun, werden diese Ausnahmen Ihr Programm beenden. Um einen Handler zu setzen, verwenden Sie die Signalfunktion, übergeben Sie das Signal, das Sie eingeschlossen haben möchten, und rufen Sie die Funktion auf, wenn das Signal ausgelöst wird.

+0

Danke! Ist es möglich zu wissen und auszudrucken, wo die Ausnahme in der Funktion auftritt, die das Signal verarbeitet? – Tim

+0

Das ist nicht wahr. Im Allgemeinen erzeugen nur Pre-754-Systeme SIGFPE für einzelne Operationen. Auch Dinge wie ungenau und Unterlauf waren nie Ausnahmen. Dieses Programm kann dazu verwendet werden, x/0, Überlauf und Unterlauf zu erzeugen. Es wird kein SIGFPE generiert.'#include #include Int Haupt (int ac, char ** av) {zurück printf ("% f \ n ", atof (av [1])/atof (av [2])); } ' – DigitalRoss

1

C99 hat Funktionen zur Behandlung von Gleitkommaausnahmen eingeführt. Vor einer Gleitkommaoperation können Sie feclearexcept() verwenden, um alle ausstehenden Ausnahmen zu löschen. Nach den Operationen können Sie dann fetestexcept() verwenden, um zu testen, welche Ausnahmebedingungen gesetzt sind.

4

Unter Windows mit Visual C++ können Sie mithilfe von _control87() etc. steuern, welche Gleitkommaausnahmen nicht maskiert werden. Nicht maskierte Gleitkommaausnahmen generieren strukturierte Ausnahmen, die mit __try/__except (und einigen anderen Mechanismen) behandelt werden können. Dies ist alles vollständig plattformabhängig. Wenn Sie Gleitkommaausnahmen maskiert lassen, besteht ein weiterer plattformabhängiger Ansatz zum Erkennen dieser Bedingungen darin, den Gleitkommastatus mithilfe von _clear87() etc. zu löschen, Berechnungen auszuführen und dann den Gleitkommastatus mithilfe von _status87() etc. abzufragen.

Ist irgendetwas davon besser als der Vorschlag von DigitalRoss, das Ergebnis zu überprüfen? In den meisten Fällen ist es nicht. Wenn Sie Rundungen erkennen (oder kontrollieren) müssen (was unwahrscheinlich ist), dann vielleicht? Bei Windows mit Borland/CodeGear/Embarcadero C++ werden einige Gleitkommaausnahmen standardmäßig nicht maskiert, was häufig Probleme verursacht, wenn Bibliotheken von Drittanbietern verwendet werden, die nicht mit unmaskierten Gleitkommaausnahmen getestet wurden.