NaNs: signaling und quiet
-
Hallo,
ich versuche gerade, den Unterschied zwischen signaling und quiet NaNs zu verstehen. Wenn ich es richtig gelesen habe, sind die signaling NaNs dazu da, dass beim Benutzen des Wertes irgendwie eine FP-Exception auftreten soll, bei quiet dagegen nicht.
Ich habe häufig den Fall, dass ich z.B. einen vector<double> mit NaNs vorinitialisiere, um nachher checken zu können, ob alle Werte auch gesetzt wurden. Sind dann hier signaling_NaNs richtig?
Und wenn ich z.B. einen Durchschnitt aus 0 Zahlen berechne, sollte man dann quiet NaNs oder signaling NaNs nehmen? (ich möchte in dem Fall nicht die Zahl 0 zurückgeben).
Aber wie unterscheiden sich die beiden NaN-Arten denn überhaupt vom praktischen Standpunkt her? Bislang habe ich noch keinen Unterschied zwischen beiden NAN-Arten gesehen, d.h. ich suche ein Programm, bei dem es einen Unterschied macht, ob ich signaling oder quiet NaN verwende. std::isnan liefert in beiden Fällen true... Oder ist das alles so undefiniert, dass man eigentlich gar nichts sagen kann?
Ich bin bislang einfach immer mit "nimm irgendein zufälliges NaN und alles ist so wie erwartet" gut gefahren, dachte aber, dass ich das vielleicht mal mit mehr Sinn und Verstand tun sollte
-
wob schrieb:
Ich habe häufig den Fall, dass ich z.B. einen vector<double> mit NaNs vorinitialisiere, um nachher checken zu können, ob alle Werte auch gesetzt wurden. Sind dann hier signaling_NaNs richtig?
Signaling.
Und wenn ich z.B. einen Durchschnitt aus 0 Zahlen berechne, sollte man dann quiet NaNs oder signaling NaNs nehmen? (ich möchte in dem Fall nicht die Zahl 0 zurückgeben).
Solltest du da überhaupt etwas spezielles nehmen? Das NaN ergibt sich doch ganz natürlich aus der Rechnung, ohne dass du Fallunterscheidungen machen musst. Der Aufrufer kann dann entscheiden, ob und wie er reagieren will.
Aber wie unterscheiden sich die beiden NaN-Arten denn überhaupt vom praktischen Standpunkt her? Bislang habe ich noch keinen Unterschied zwischen beiden NAN-Arten gesehen, d.h. ich suche ein Programm, bei dem es einen Unterschied macht, ob ich signaling oder quiet NaN verwende. std::isnan liefert in beiden Fällen true... Oder ist das alles so undefiniert, dass man eigentlich gar nichts sagen kann?
Mit signaling NaN kannst du nicht ohne Fehler weiterrechnen:
#include <iostream> #include <limits> #include <cfenv> #pragma STDC FENV_ACCESS ON void test(double d) { std::feclearexcept(FE_ALL_EXCEPT); double dd = d+1; if (std::fetestexcept(FE_ALL_EXCEPT)) std::cout << "Exception!\n" ; else std::cout << "Alles ok!\n"; } int main() { test(std::numeric_limits<double>::quiet_NaN()); test(std::numeric_limits<double>::signaling_NaN()); }
Man beachte, dass floating point exceptions nichts mit C++-Exceptions zu tun haben.
-
Also verstehe ich das richtig: wenn ich nicht aktiv selbst mit fetestexcept überprüfe, ob ein Fehler aufgetreten ist, dann gibt es keinen Unterschied (oder natürlich wenn jemand anderes dieses Flag testet)?
Allerdings bekomme ich
warning: pragma STDC FENV_ACCESS ON is not supported, ignoring pragma [-Wunknown-pragmas]
Und ich bekomme unterschiedliche Ergebnisse raus, je nachdem, ob ich cling oder clang nehme... Na toll!
cling interaktiv: in beiden Fällen wird liefert fetestexcept 33 = FE_INEXACT+FE_INVALID
cling nicht interaktiv: 2x "alles ok" (also das Gegenteil!)
clang++-3.9 einmal ok bei quiet, exception bei signaling (so wie du es beschrieben hast)
-
Ja, das ganze Thema ist ein bisschen heikel (bzw. optional) von der Unterstützung her. So ist das eben, wenn man etwas, das eigentlich ein Hardwarefeature ist, in einer hardwareunabhängigen Sprache zur Verfügung stellt.
Apropos Unportabel: Viele Compiler haben auch Features, um aus den FP Exceptions echte C++ Exceptions zu machen.