Kann ein Gleitkommawert nahe Null einen Division-durch-Null-Fehler verursachen?

Lesezeit: 10 Minuten

Benutzeravatar von neuviemeporte
neuviemeporte

Jeder weiß, dass Floats nicht direkt verglichen werden sollen, sondern mit einer Toleranz:

float a,b;
float epsilon = 1e-6f;
bool equal = (fabs(a-b) < epsilon);

Ich habe mich gefragt, ob dasselbe für den Vergleich eines Werts mit Null gilt, bevor er in der Division verwendet wird.

float a, b;
if (a != 0.0f) b = 1/a; // oops?

Muss ich in diesem Fall auch mit epsilon vergleichen?

  • Suchen Sie überhaupt nicht nach 0. Lass es hart krachen!

    – Luchian Grigore

    24. August 2012 um 18:05 Uhr

  • Jeder weiß, dass Floats nicht mit einer Toleranz verglichen werden sollen, sondern auf eine Weise, die für das, was Sie wollen, sinnvoll ist. @LuchianGrigore es wird nicht abstürzen.

    – R.Martinho Fernandes

    24. August 2012 um 18:05 Uhr


  • Sie erhalten keine Fehler, wenn b nicht genau 0 ist. Wenn b jedoch zu klein ist, ergibt das Ergebnis möglicherweise keinen Sinn, dies hängt von Ihrer Anwendungslogik ab.

    – Denys Séguret

    24. August 2012 um 18:07 Uhr


  • @LuchianGrigore Nur wenn Sie nicht wissen, was Sie bei 0 tun sollen. Aber ich bin mir ziemlich sicher, dass es Fälle gibt, in denen es sinnvoll ist, 0 besonders zu behandeln. Außerdem bringen es nicht alle Umgebungen zum Absturz, einige geben Ihnen nur einen seltsamen Wert (ich bin mir nicht sicher, ob es NaN, eine der Unendlichkeiten oder etwas anderes ist).

    Benutzer395760

    24. August 2012 um 18:07 Uhr


  • Erwägen Sie möglicherweise die Verwendung Q-Nummernwenn sie für Ihre Situation geeignet sind …

    – 0909EM

    24. August 2012 um 18:08 Uhr

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Eine Gleitkommadivision durch Null ist kein Fehler. Es löst eine Gleitkomma-Ausnahme aus (was keine Operation ist, es sei denn, Sie prüfen sie aktiv) bei Implementierungen, die Gleitkomma-Ausnahmen unterstützen, und hat ein klar definiertes Ergebnis: entweder positiv oder negativ unendlich (wenn der Zähler ungleich Null ist) oder NAN (wenn der Zähler Null ist).

Es ist auch möglich, unendlich (und eine Überlaufausnahme) als Ergebnis zu erhalten, wenn der Nenner nicht Null, aber sehr nahe bei Null liegt (z. B. subnormal), aber auch dies ist kein Fehler. So funktioniert Gleitkommazahl.

Bearbeiten: Beachten Sie, dass diese Antwort, wie Eric in den Kommentaren ausgeführt hat, die Anforderungen von Anhang F voraussetzt, einem optionalen Teil des C-Standards, der das Gleitkommaverhalten detailliert und an den IEEE-Standard für Gleitkommazahlen anpasst. In Ermangelung von IEEE-Arithmetik definiert C keine Gleitkommadivision durch Null (und tatsächlich sind die Ergebnisse aller Gleitkommaoperationen implementierungsdefiniert und können als völliger Unsinn definiert werden und dennoch dem C-Standard entsprechen), also wenn Wenn Sie es mit einer ausgefallenen C-Implementierung zu tun haben, die IEEE-Gleitkommazahlen nicht berücksichtigt, müssen Sie die Dokumentation für die von Ihnen verwendete Implementierung konsultieren, um diese Frage zu beantworten.

  • Lassen Sie mich unterstreichen: eine Fließkomma-Ausnahme ist nicht eine C++-Ausnahme. Sie können keinen Try-Catch-Block darum herum setzen. Sie werden es nicht sehen, wenn Sie nicht darauf aus sind, und das erfordert ein wenig Fachwissen. Wie @R.. sagte, ist es ein No-Op, es sei denn, Sie wissen, wie Sie es finden. Und Sie wollen das nicht tun, es sei denn, Sie sind ein Experte.

    – Peter Becker

    24. August 2012 um 18:39 Uhr


  • Danke Pete für die Betonung dieses Punktes. Es sei denn, Sie verwenden fenv.h (Die meisten Leute haben nicht einmal gehört von es, geschweige denn verwendet), Gleitkommaausnahmen sind irrelevant/no-ops.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    24. August 2012 um 18:41 Uhr

  • Der C-Standard definiert nicht die Standard-Gleitkommaumgebung, es sei denn, eine Implementierung übernimmt Anhang F. Ohne Anhang F können Traps standardmäßig aktiviert werden. Die Verwendung von Hochleistungsoptionen beim Kompilieren kann Modi aktivieren, die nicht dem C-Standard oder IEEE 754 entsprechen. Eine pauschale Aussage, dass eine Division durch Null kein Fehler ist, ist nicht gerechtfertigt.

    – Eric Postpischil

    24. August 2012 um 19:07 Uhr

  • Ohne Anhang F gibt es grundsätzlich keine Anforderungen an das Verhalten von Gleitkommazahlen. 2.0+2.0==5.0 kann wahr sein. Es ist sinnlos, in C über Fließkommazahlen zu sprechen, ohne Anhang F vorauszusetzen.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    24. August 2012 um 19:43 Uhr

  • Können Sie bitte den Teil des C-Standards zitieren, der impliziert 2.0+2.0!=5.0? Eine solche Anforderung ist mir nicht bekannt.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    24. August 2012 um 20:38 Uhr

Benutzeravatar von Eric Postpischil
Eric Postpischil

Ja, das Teilen durch kleine Zahlen kann in manchen Situationen die gleichen Auswirkungen haben wie das Teilen durch Null, einschließlich Traps.

Einige C-Implementierungen (und einige andere Computerumgebungen) können in einem Flush-Underflow-Modus ausgeführt werden, insbesondere wenn Optionen für hohe Leistung verwendet werden. In diesem Modus kann die Division durch eine Subnormale dasselbe Ergebnis erzielen wie die Division durch Null. Der Flush-Underflow-Modus ist nicht ungewöhnlich, wenn Vektorbefehle (SIMD) verwendet werden.

Subnormale Zahlen sind solche mit dem minimalen Exponenten im Fließkommaformat, die so klein sind, dass das implizite Bit des Signifikanten 0 statt 1 ist. Für IEEE 754 mit einfacher Genauigkeit sind dies Zahlen ungleich Null mit einer Größe von weniger als 2-126. Bei doppelter Genauigkeit handelt es sich um Zahlen ungleich Null mit einer Größe von weniger als 2-1022.

Der korrekte Umgang mit subnormalen Zahlen (gemäß IEEE 754) erfordert bei manchen Prozessoren zusätzliche Rechenzeit. Um diese Verzögerung zu vermeiden, wenn sie nicht benötigt wird, können Prozessoren einen Modus haben, der subnormale Operanden in Null umwandelt. Die Division einer Zahl durch einen subnormalen Operanden ergibt dann das gleiche Ergebnis wie die Division durch Null, auch wenn das übliche Ergebnis endlich wäre.

Wie in anderen Antworten erwähnt, ist das Teilen durch Null kein Fehler in C-Implementierungen, die Anhang F des C-Standards übernehmen. Nicht alle Implementierungen, die dies tun. In Implementierungen, die dies nicht tun, können Sie ohne zusätzliche Angaben zu Ihrer Umgebung nicht sicher sein, ob Floating-Point-Traps aktiviert sind, insbesondere der Trap für die Division-durch-Null-Ausnahme.

Abhängig von Ihrer Situation müssen Sie sich möglicherweise auch davor schützen, dass anderer Code in Ihrer Anwendung die Gleitkommaumgebung ändert.

  • Völlig pingelig: Die Revision von IEEE-754 von 2008 hat “denormal” in “subnormal” geändert. Diese Änderung der Terminologie ändert nichts an den oben genannten Punkten.

    – Peter Becker

    24. August 2012 um 19:26 Uhr

  • requires additional computing time in some processors Tatsächlich ist es nicht drin etwas Prozessoren – es ist in die meisten der aktuellen Prozessoren, einschließlich x86- und ARM-Prozessoren.

    – Ruslan

    11. August 2015 um 8:36 Uhr


Benutzeravatar von Sergey Kalinichenko
Sergej Kalinitschenko

Um die Frage im Titel Ihres Beitrags zu beantworten, führt die Division durch eine sehr kleine Zahl nicht zu einer Division durch Null, aber es kann dazu führen, dass das Ergebnis unendlich wird:

double x = 1E-300;
cout << x << endl;
double y = 1E300;
cout << y << endl;
double z = y / x;
cout << z << endl;
cout << (z == std::numeric_limits<double>::infinity()) << endl;

Dies produziert folgende Ausgabe:

1e-300
1e+300
inf
1

  • Ist es möglich zu testen, ob ein Wert unendlich ist?

    – neuviemeporte

    24. August 2012 um 18:36 Uhr

  • z!=z ist für unendlich falsch. Das gilt nur für Omas.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    24. August 2012 um 18:41 Uhr

  • @neuviemeporte Ja – schau dir das Update zur Antwort an.

    – Sergej Kalinitschenko

    24. August 2012 um 18:42 Uhr

  • @R .. Danke, ich habe den Trick überprüft, und er hat nicht funktioniert, also habe ich ihn länger überprüft.

    – Sergej Kalinitschenko

    24. August 2012 um 18:43 Uhr

  • @neuviemeporte Seit C99 in math.h das Makro int isfinite(float x) definiert, die nur dann ein Ergebnis ungleich Null zurückgibt, wenn x endlich ist. Siehe pubs.opengroup.org/onlinepubs/009604499/functions/isfinite.html

    – Halex

    24. August 2012 um 18:55 Uhr

Benutzeravatar von Jens Agby
Jens Agby

Nur eine Division durch genau 0.f löst eine Division-durch-Null-Ausnahme aus.

Die Division durch eine sehr kleine Zahl kann jedoch eine Überlaufausnahme erzeugen – das Ergebnis ist so groß, dass es nicht mehr durch einen Float dargestellt werden kann. Die Division gibt Unendlich zurück.

Die Float-Darstellung von Unendlich kann in Berechnungen verwendet werden, sodass Sie möglicherweise nicht prüfen müssen, ob der Rest Ihrer Implementierung damit umgehen kann.

Benutzeravatar von Reed Copsey
Reed Copsey

Muss ich in diesem Fall auch mit epsilon vergleichen?

Sie werden niemals einen Division-durch-Null-Fehler erhalten, da 0.0f ist genau in an dargestellt IEEE-Float.

Davon abgesehen möchten Sie vielleicht immer noch etwas Toleranz verwenden – obwohl dies vollständig von Ihrer Anwendung abhängt. Wenn der „Null“-Wert das Ergebnis einer anderen Mathematik ist, ist es möglich, eine sehr kleine Zahl ungleich Null zu erhalten, was zu einem führen kann unerwartet Ergebnis nach Ihrer Division. Wenn Sie “nahe Null”-Zahlen als Null behandeln möchten, wäre eine Toleranz angebracht. Dies hängt jedoch ganz von Ihrer Anwendung und Ihren Zielen ab.

Wenn Ihr Compiler verwendet IEEE 754-Standards für die Ausnahmebehandlung, dann dividieren durch Null, sowie eine Division durch einen Wert, der klein genug ist, um einen Überlauf zu verursachen, würden beide einen Wert von +/- unendlich ergeben. Dies könnte bedeuten, dass Sie die Prüfung auf sehr kleine Zahlen einschließen möchten (das würde einen Überlauf auf Ihrer Plattform verursachen). Zum Beispiel auf Fenster, float und double beide entsprechen den Spezifikationen, was dazu führen kann, dass ein sehr kleiner Teiler +/- unendlich erzeugt, genau wie ein Nullwert.

Wenn Ihr Compiler / Ihre Plattform nicht den IEEE 754-Gleitkommastandards entspricht, sind die Ergebnisse meiner Meinung nach plattformspezifisch.

  • War das wirklich die Frage? Es ist großartig, dass 0 genau dargestellt wird, aber bedeutet das, dass kein anderer Wert das gleiche Ergebnis haben kann wie die Division durch Null?

    Benutzer395760

    24. August 2012 um 18:09 Uhr

  • @delnan Es ist nicht ganz klar – angesichts der Frage “Kann ein Gleitkommawert nahe Null einen Division-durch-Null-Fehler verursachen?” – Ja, ich denke, das beantwortet es direkt;) Ich habe jedoch versucht, andere Punkte in meiner Antwort anzusprechen …

    – Reed Copsey

    24. August 2012 um 18:10 Uhr

  • Ich beziehe mich auch auf diesen Teil der Frage. Immerhin ist es denkbar (für ungebildete mich), dass einige Werte, die extrem nahe bei Null liegen, die gleiche Gleitkomma-Ausnahme verursachen wie die Division durch exakte Null. -1 für jetzt.

    Benutzer395760

    24. August 2012 um 18:12 Uhr


  • @delnan Normalerweise ist eine echte “Division durch Null” wirklich nur eine Division durch Null. Ich glaube jedoch, dass dies plattformspezifisch sein kann – zum Beispiel wird div/0 unter Windows EXCEPTION_FLT_DIVIDE_BY_ZERO auslösen, indem ich glaube, dass div/(nr 0) EXCEPTION_FLT_OVERFLOW unter Windows auslösen kann – Siehe: msdn.microsoft.com/en-us/library/windows/desktop/…

    – Reed Copsey

    24. August 2012 um 18:15 Uhr

  • @delnan Hinzugefügt (nach dem Nachschlagen) die IEEE 754-Gleitkommaregeln – das ist wahrscheinlich das, was einem “Standard” dafür am nächsten kommt, der verwendet werden kann.

    – Reed Copsey

    24. August 2012 um 18:22 Uhr

  • War das wirklich die Frage? Es ist großartig, dass 0 genau dargestellt wird, aber bedeutet das, dass kein anderer Wert das gleiche Ergebnis haben kann wie die Division durch Null?

    Benutzer395760

    24. August 2012 um 18:09 Uhr

  • @delnan Es ist nicht ganz klar – angesichts der Frage “Kann ein Gleitkommawert nahe Null einen Division-durch-Null-Fehler verursachen?” – Ja, ich denke, das beantwortet es direkt;) Ich habe jedoch versucht, andere Punkte in meiner Antwort anzusprechen …

    – Reed Copsey

    24. August 2012 um 18:10 Uhr

  • Ich beziehe mich auch auf diesen Teil der Frage. Immerhin ist es denkbar (für ungebildete mich), dass einige Werte, die extrem nahe bei Null liegen, die gleiche Gleitkomma-Ausnahme verursachen wie die Division durch exakte Null. -1 für jetzt.

    Benutzer395760

    24. August 2012 um 18:12 Uhr


  • @delnan Normalerweise ist eine echte “Division durch Null” wirklich nur eine Division durch Null. Ich glaube jedoch, dass dies plattformspezifisch sein kann – zum Beispiel wird div/0 unter Windows EXCEPTION_FLT_DIVIDE_BY_ZERO auslösen, indem ich glaube, dass div/(nr 0) EXCEPTION_FLT_OVERFLOW unter Windows auslösen kann – Siehe: msdn.microsoft.com/en-us/library/windows/desktop/…

    – Reed Copsey

    24. August 2012 um 18:15 Uhr

  • @delnan Hinzugefügt (nach dem Nachschlagen) die IEEE 754-Gleitkommaregeln – das ist wahrscheinlich das, was einem “Standard” dafür am nächsten kommt, der verwendet werden kann.

    – Reed Copsey

    24. August 2012 um 18:22 Uhr

1414900cookie-checkKann ein Gleitkommawert nahe Null einen Division-durch-Null-Fehler verursachen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy