C-Standardbibliothek<fenv.h>
C-Standardbibliothek<fenv.h>
<fenv.h>ist eine Header-Datei in der C-Standardbibliothek, die zur Steuerung der Gleitkommaumgebung verwendet wird.
<fenv.h>Im C99-Standard eingeführt, bietet sie Funktionalität zur Steuerung und Abfrage von Gleitkomma-Ausnahmen, Rundungsmodi und anderen Gleitkomma-Zuständen.
<fenv.h>Der Hauptzweck ist:
-
Erkennen und Behandeln von Gleitkomma-Ausnahmen (wie Division durch Null, Überlauf usw.).
-
Steuern des Rundungsmodus für Gleitkommaoperationen (wie Rundung gegen Null, Rundung auf den nächsten Wert usw.).
-
Abfragen und Ändern von Gleitkomma-Statusflags.
1, Gleitkomma-Ausnahmen
Gleitkomma-Ausnahmen sind besondere Situationen, die während Gleitkommaoperationen auftreten, zum Beispiel:
-
FE_DIVBYZERO: Division durch Null.
-
FE_INEXACT: Ungenaues Ergebnis.
-
FE_INVALID: ungültige Operation (wie das Ziehen der Quadratwurzel aus einer negativen Zahl).
-
FE_OVERFLOW: Überlauf.
-
FE_UNDERFLOW: Unterlauf.
Diese Ausnahmen werden durch Gleitkomma-Statusflags repräsentiert und können<fenv.h>Die darin enthaltenen Funktionen erkennen und behandeln.
2, Rundungsmodi
Der Rundungsmodus steuert, wie die Ergebnisse von Gleitkommaoperationen gerundet werden.<fenv.h>Die folgenden Rundungsmodi sind definiert:
-
FE_TONEAREST: auf den nächstgelegenen Wert runden (Standardmodus).
-
FE_DOWNWARD: Richtung negative Unendlichkeit runden.
-
FE_UPWARD: Richtung positive Unendlichkeit runden.
-
FE_TOWARDZERO: Richtung null runden.
3, Hauptfunktionen und Makros
<fenv.h>Stellt eine Reihe von Funktionen und Makros für die Manipulation der Gleitkommaumgebung und die Behandlung von Gleitkommaausnahmen bereit.
Behandlung von Gleitkommaausnahmen
| Funktionen/Makros | Beschreibung |
|---|---|
feclearexcept(int excepts) |
Die angegebenen Gleitkomma-Ausnahmeflags löschen |
feraiseexcept(int excepts) |
Die angegebene Gleitkomma-Ausnahme auslösen |
fetestexcept(int excepts) |
Testen, ob die angegebene Gleitkomma-Ausnahme aufgetreten ist |
fegetexceptflag(fexcept_t *flagp, int excepts) |
Status des Gleitkomma-Ausnahmeflags abrufen |
fesetexceptflag(const fexcept_t *flagp, int excepts) |
Status des Gleitkomma-Ausnahmeflags setzen |
Rundungsmodus-Steuerung
| Funktionen/Makros | Beschreibung |
|---|---|
fegetround(void) |
Aktuellen Rundungsmodus abrufen |
fesetround(int round) |
Aktuellen Rundungsmodus setzen |
Steuerung der Gleitkommaumgebung
| Funktionen/Makros | Beschreibung |
|---|---|
fegetenv(fenv_t *envp) |
Aktuelle Gleitkommaumgebung speichern |
fesetenv(const fenv_t *envp) |
Wiederherstellen der Gleitkommaumgebung |
feholdexcept(fenv_t *envp) |
Aktuelle Gleitkommaumgebung speichern und Ausnahmeflags löschen. |
feupdateenv(const fenv_t *envp) |
Gleitkommaumgebung wiederherstellen und Ausnahmen auslösen |
4, Beispiel
Das Folgende ist ein Beispiel unter Verwendung von<fenv.h>Ein Beispiel hierfür, das zeigt, wie man Gleitkomma-Ausnahmen erkennt und den Rundungsmodus steuert:
Beispiel
#include <fenv.h>
#include <math.h>
int main() {
// Erkennung von Gleitkomma-Ausnahmen aktivieren
feclearexcept(FE_ALL_EXCEPT);
// Division-durch-Null-Ausnahme auslösen
double x = 1.0, y = 0.0;
double z = x / y;
// Prüfen, ob eine Division-durch-Null-Ausnahme aufgetreten ist
if (fetestexcept(FE_DIVBYZERO)) {
printf("Division-durch-Null-Ausnahme aufgetreten.\n");
}
// Rundungsmodus auf Rundung gegen Null setzen
fesetround(FE_TOWARDZERO);
// Rundungsmodus testen
double a = 1.5;
double b = rint(a); // Auf Ganzzahl runden
printf("Rundung von 1.5 gegen null: %.1f\n", b);
return 0;
}
Das Ausgabeergebnis ist:
Divide by zero exception occurred. Rounding 1.5 toward zero: 1.0
Erkennen von Gleitkomma-Ausnahmen
Beispiel
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
void check_exceptions() {
// Alle Ausnahme-Flags löschen
feclearexcept(FE_ALL_EXCEPT);
// Operationen ausführen, die Ausnahmen auslösen können
double x = 0.0;
double y = 1.0 / x; // Division durch null
// Auf eine bestimmte Ausnahme prüfen
if (fetestexcept(FE_DIVBYZERO)) {
printf("Division durch null ist aufgetreten!\n");
}
// Auf eine beliebige Ausnahme prüfen
if (fetestexcept(FE_ALL_EXCEPT)) {
printf("Mindestens eine Gleitkomma-Ausnahme ist aufgetreten\n");
}
}
int main() {
check_exceptions();
return 0;
}
Rundungsrichtung steuern
Beispiel
#include <stdio.h>
#pragma STDC FENV_ACCESS ON
void test_rounding(double num) {
int modes[] = {FE_TONEAREST, FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO};
const char *names[] = {"Nächste", "Aufwärts", "Abwärts", "Richtung Null"};
for (int i = 0; i < 4; i++) {
if (fesetround(modes[i]) == 0) {
printf("Rundung %s: %.1f -> %.0f\n",
names[i], num, rint(num));
}
}
}
int main() {
test_rounding(2.5); // Teste das Ergebnis von 2.5 in verschiedenen Rundungsmodi
test_rounding(-2.5); // Testen Sie das Ergebnis von -2.5 in verschiedenen Rundungsmodi
return 0;
}
Gleitkommaumgebung speichern und wiederherstellen
Beispiel
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
void sensitive_calculation() {
fenv_t env;
// Aktuelle Umgebung speichern
fegetenv(&env);
// Strikte Umgebung setzen: alle Ausnahmen abfangen
feclearexcept(FE_ALL_EXCEPT);
// Kritische Berechnung durchführen
double result = sqrt(-1.0); // Ungültige Operation
if (fetestexcept(FE_INVALID)) {
printf("Ungültige Operation in sensibler Berechnung erkannt\n");
}
// Ursprüngliche Umgebung wiederherstellen
fesetenv(&env);
}
int main() {
sensitive_calculation();
return 0;
}
Ausnahmen vorübergehend maskieren
Beispiel
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
void temp_disable_exceptions() {
fenv_t env;
// Umgebung speichern und alle Ausnahmen vorübergehend maskieren
feholdexcept(&env);
// Operationen ausführen, die Ausnahmen auslösen können
double x = 0.0;
double y = 1.0 / x; // Es werden keine Ausnahmen ausgelöst
printf("Eine Division durch Null wurde durchgeführt, aber nicht gemeldet\n");
// Umgebung wiederherstellen und zuvor aufgetretene Ausnahmen behandeln
feupdateenv(&env);
// Nun können Ausnahmen geprüft werden
if (fetestexcept(FE_DIVBYZERO)) {
printf("Eine Division durch Null wurde nach Wiederherstellung der Umgebung erkannt\n");
}
}
int main() {
temp_disable_exceptions();
return 0;
}
Beispiel für exakte Berechnung
Beispiel
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
double precise_sum(double a, double b) {
int original_round = fegetround();
fenv_t env;
// Umgebung speichern und höchsten Genauigkeitsmodus einstellen
fegetenv(&env);
fesetround(FE_TONEAREST);
feclearexcept(FE_ALL_EXCEPT);
double result = a + b;
// Prüfen, ob die Berechnung exakt ist
if (fetestexcept(FE_INEXACT)) {
printf("Warnung: Summe war nicht exakt, möglicher Genauigkeitsverlust\n");
}
// Ursprüngliche Umgebung wiederherstellen
fesetround(original_round);
fesetenv(&env);
return result;
}
int main() {
double a = 1.0 / 3.0;
double b = 2.0 / 3.0;
printf("Summe: %.17g\n", precise_sum(a, b));
return 0;
}
Wrapper für Ausnahmebehandlung
Beispiel
#include <stdio.h>
#include <math.h>
#pragma STDC FENV_ACCESS ON
typedef double (*math_func)(double);
double safe_math(math_func f, double x, int *error) {
fenv_t env;
*error = 0;
feclearexcept(FE_ALL_EXCEPT);
fegetenv(&env);
double result = f(x);
int exceptions = fetestexcept(FE_ALL_EXCEPT);
if (exceptions) {
*error = exceptions;
if (exceptions & FE_INVALID) printf("Ungültige Operation\n");
if (exceptions & FE_DIVBYZERO) printf("Division durch Null\n");
if (exceptions & FE_OVERFLOW) printf("Überlauf\n");
if (exceptions & FE_UNDERFLOW) printf("Unterlauf\n");
if (exceptions & FE_INEXACT) printf("Ungenaues Ergebnis\n");
}
fesetenv(&env);
return result;
}
int main() {
int error;
double a = safe_math(sqrt, -1.0, &error);
printf("sqrt(-1) = %f (error: %d)\n", a, error);
double b = safe_math(log, 0.0, &error);
printf("log(0) = %f (error: %d)\n", b, error);
return 0;
}
5, Hinweise
Bevor Funktionen der Gleitkommaumgebung verwendet werden, ist es normalerweise notwendig,#pragma STDC FENV_ACCESS ONzu aktivieren, um den Compiler darüber zu informieren, dass Operationen der Gleitkommaumgebung nicht wegoptimiert werden.
-
Nicht alle Implementierungen unterstützen alle Funktionen; vor der Verwendung sollte geprüft werden, ob das Makro FE_DFL_ENV definiert ist.
-
<fenv.h>Nur in C99 und späteren Versionen verfügbar. -
Das spezifische Verhalten bei der Erkennung von Gleitkomma-Ausnahmen und der Steuerung des Rundungsmodus kann von der Hardware- und Compiler-Implementierung abhängen.
-
Auf einigen Plattformen können Gleitkomma-Ausnahmen standardmäßig maskiert sein, und sie müssen
feenableexceptdurch andere Funktionen explizit aktiviert werden. -
Operationen der Gleitkommaumgebung können die Leistung beeinflussen und sollten mit Vorsicht verwendet werden.
<fenv.h>Bietet Steuerfunktionen für die Gleitkommaumgebung, einschließlich der Erkennung und Behandlung von Gleitkomma-Ausnahmen, der Einstellung von Rundungsmodi sowie der Abfrage und Änderung des Gleitkomma-Zustands. Es ist ein leistungsstarkes Werkzeug für hochpräzise Gleitkommaberechnungen und die Fehlersuche bei Gleitkommaproblemen, besonders geeignet für wissenschaftliches Rechnen und technische Anwendungen. Durch die Verwendung von<fenv.h>, Entwickler können das Verhalten von Gleitkommaoperationen besser steuern und so die Genauigkeit und Zuverlässigkeit der Berechnungsergebnisse gewährleisten.