13 Stimmen

Umgang mit Fließkomma-Ausnahmen

Ich bin mir nicht sicher, wie man mit Fließkommaausnahmen in C oder C++ umgeht. Laut Wiki gibt es die folgenden Arten von Fließkomma-Ausnahmen:

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.

Wenn eine der oben genannten Ausnahmen auftritt, wird das Programm dann abnormal beendet? Oder führt das Programm diesen Fehler weiter, ohne etwas zu sagen, und erschwert so die Fehlersuche?

Ist ein Compiler wie gcc in der Lage, Warnung für einige offensichtliche Fall geben?

Was kann ich während der Codierung meines Programms tun, um mitzuteilen, wo der Fehler auftritt und um welche Art von Fehler es sich handelt, wenn er auftritt, so dass ich den Fehler in meinem Code leicht finden kann? Bitte geben Sie Lösungen sowohl für C als auch für C++ an.

Vielen Dank und herzliche Grüße!

12voto

DigitalRoss Punkte 138823

Es gibt viele Optionen, aber die allgemeine und auch die Standardphilosophie, die mit 754 eingeführt wurde, lautet no Falle zu vermeiden, sondern stattdessen spezielle Ergebnisse wie Unendlichkeiten zu erzeugen, die in wichtigen Ergebnissen auftauchen können oder auch nicht.

Daher werden die Funktionen, die den Zustand der einzelnen Operationen testen, nicht so häufig 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)

Aktualisieren: Wer wirklich glaubt, dass FPU-Ops heutzutage standardmäßig SIGFPE erzeugen, dem empfehle ich, dieses Programm auszuprobieren. Sie können leicht Unterlauf, Überlauf und Teilung durch Null erzeugen. Was Sie nicht erzeugen werden (es sei denn, Sie lassen es auf der 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])); }

6voto

Mike Dinsdale Punkte 1481

Unter Linux können Sie die GNU-Erweiterung feenableexceptive (ganz unten auf dieser Seite versteckt), um das Abfangen von Fließkomma-Ausnahmen einzuschalten - wenn Sie dies tun, erhalten Sie das Signal SIGFPE, wenn eine Ausnahme auftritt, die Sie dann in Ihrem Debugger abfangen können. Seien Sie jedoch vorsichtig, denn manchmal wird das Signal bei der Fließkommaanweisung ausgelöst après diejenige, die das Problem tatsächlich verursacht und irreführende Zeileninformationen im Debugger liefert!

4voto

bk1e Punkte 23191

Unter Windows mit Visual C++ können Sie steuern, welche Gleitkommaausnahmen demaskiert werden, indem Sie _control87() usw. . Unmaskierte Gleitkommaausnahmen erzeugen strukturierte Ausnahmen, die mit __try / __except (und eine Reihe anderer Mechanismen). Dies alles ist völlig plattformabhängig.

Wenn Sie Fließkommaausnahmen maskiert lassen, besteht ein weiterer plattformabhängiger Ansatz zur Erkennung dieser Bedingungen darin, den Fließkommastatus mit _clear87() usw. , führen Sie Berechnungen durch, und fragen Sie dann den Gleitkommastatus mit _status87() usw. .

Ist irgendetwas davon besser als der Vorschlag von DigitalRoss, das Ergebnis zu überprüfen? In den meisten Fällen nicht. Wenn Sie Rundungen erkennen (oder kontrollieren) müssen (was unwahrscheinlich ist), dann vielleicht?

Unter Windows mit Borland/CodeGear/Embarcadero C++ sind einige Fließkomma-Ausnahmen standardmäßig unmaskiert, was häufig zu Problemen führt, wenn Bibliotheken von Drittanbietern verwendet werden, die nicht mit unmaskierten Fließkomma-Ausnahmen getestet wurden.

2voto

Arthur Kalliokoski Punkte 1470

Verschiedene Compiler behandeln diese Fehler auf unterschiedliche Weise.

Ungenauigkeit ist fast immer das Ergebnis der Division von Zahlen mit einem Absolutwert größer als eins (vielleicht durch Transzendentalfunktionen). Das Addieren, Subtrahieren und Multiplizieren von Zahlen mit einem Absolutwert > 1,0 kann nur zu einem Überlauf führen.

Ein Unterlauf tritt nicht sehr häufig auf und ist bei normalen Berechnungen wahrscheinlich kein Problem, außer bei iterierten Funktionen wie Taylor-Reihen.

Ein Überlauf ist ein Problem, das in der Regel durch eine Art "Unendlichkeits"-Vergleich erkannt werden kann, wobei die verschiedenen Compiler variieren.

Das Teilen durch Null ist ziemlich auffällig, da Ihr Programm abstürzt (abstürzen sollte), wenn Sie keinen Fehler-Handler haben. Die Überprüfung von Dividenden und Divisoren hilft, das Problem zu vermeiden.

Ungültige Antworten werden in der Regel ohne spezielle Fehlerbehandlungsprogramme mit einer Art DOMAIN-Fehlerausdruck abgefangen.

[EDIT]

Das könnte helfen: (Leitfaden für numerische Berechnungen von Sun) http://docs.sun.com/source/806-3568/

1voto

caf Punkte 224189

C99 führte Funktionen zur Behandlung von Fließkommaausnahmen ein. Vor einer Fließkomma-Operation können Sie mit feclearexcept() um alle ausstehenden Ausnahmen zu löschen. Nach der/den Operation(en) können Sie dann mit fetestexcept() um zu prüfen, welche Ausnahmeflags gesetzt sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X