webentwicklung-frage-antwort-db.com.de

Prüfen, ob in C++ ein Double (oder Float) NaN ist

Gibt es eine isnan () - Funktion?

PS .: Ich bin in MinGW (wenn das einen Unterschied macht).

Ich hatte das Problem gelöst, indem ich isnan () von <math.h> verwendete, was in <cmath> nicht existiert, was ich zuerst #includeing war.

340
hasen

Gemäß dem IEEE-Standard haben NaN-Werte die ungerade Eigenschaft, dass Vergleiche, an denen sie beteiligt sind, immer falsch sind. Das heißt, für einen Float f ist f != f nur dann wahr , wenn f NaN ist.

Beachten Sie, dass nicht alle Compiler dies bei der Codeoptimierung berücksichtigen, wie in den folgenden Kommentaren ausgeführt wurde.

Für jeden Compiler, der behauptet, IEEE-Gleitkomma zu verwenden, sollte dieser Trick funktionieren. Aber ich kann nicht garantieren, dass es in der Praxis funktionieren wird . Fragen Sie im Zweifelsfall Ihren Compiler.

338
jalf

In der aktuellen C++ - Standardbibliothek ist keine isnan()-Funktion verfügbar. Es wurde in C99 eingeführt und als Makro definiert, nicht als Funktion. Durch C99 definierte Elemente der Standardbibliothek sind weder Bestandteil der aktuellen C++ - Norm ISO/IEC 14882: 1998 noch deren Aktualisierung ISO/IEC 14882: 2003.

2005 wurde der Technische Bericht 1 vorgeschlagen. Der TR1 bringt Kompatibilität mit C99 nach C++. Trotz der Tatsache, dass es nie offiziell angenommen wurde, C++ - Standard zu werden, bieten viele ( GCC 4.0+ oder Visual C++ 9.0+ C++ - Implementierungen TR1-Funktionen, alle oder nur einige (Visual C++ 9.0 bietet keine mathematischen C99-Funktionen).

Wenn TR1 verfügbar ist, enthält cmath C99-Elemente wie isnan(), isfinite() usw., die jedoch als Funktionen und nicht als Makros definiert werden, normalerweise im std::tr1::-Namespace, jedoch bei vielen Implementierungen (z. B. GCC 4+ unter Linux oder XCode unter Mac OS X 10.5) +) direkt in std:: einfügen, so dass std::isnan eindeutig definiert ist.

Darüber hinaus machen einige Implementierungen von C++ das C99-Makro isnan() noch für C++ verfügbar (eingeschlossen durch cmath oder math.h). Dies kann weitere Verwirrungen verursachen, und Entwickler können davon ausgehen, dass es sich um ein Standardverhalten handelt.

Ein Hinweis zu Viusal C++, wie oben erwähnt, enthält weder std::isnan noch std::tr1::isnan, sondern eine Erweiterungsfunktion, definiert als _isnan(), die seit Visual C++ 6.0 verfügbar ist.

Auf XCode macht es noch mehr Spaß. Wie bereits erwähnt, definiert GCC 4+ std::isnan. Bei älteren Versionen des Compilers und der Bibliothek von XCode scheint es (hier ist relevante Diskussion ), ich hatte keine Gelegenheit, mich selbst zu überprüfen. Zwei Funktionen sind definiert: __inline_isnand() auf Intel und __isnand() auf Power PC.

213
mloskot

Erste Lösung: Wenn Sie C++ 11 verwenden

Da dies gefragt wurde, gab es einige neue Entwicklungen: Es ist wichtig zu wissen, dass std::isnan() Teil von C++ 11 ist

Zusammenfassung

In Header <cmath> definiert

bool isnan( float arg ); (since C++11)
bool isnan( double arg ); (since C++11)
bool isnan( long double arg ); (since C++11)

Bestimmt, ob die angegebene Gleitkommazahl arg keine Zahl ist (NaNname__).

Parameter

argname__: Gleitkommawert

Rückgabewert

truewenn arg NaNist, falseansonsten

Referenz

http://en.cppreference.com/w/cpp/numeric/math/isnan

Bitte beachten Sie, dass dies mit -fast-math nicht kompatibel ist, wenn Sie g ++ verwenden. Weitere Vorschläge finden Sie weiter unten.


Andere Lösungen: Wenn Sie nicht C++ 11-kompatible Tools verwenden

Für C99 wird dies in C als Makro isnan(c) implementiert, das einen int-Wert zurückgibt. Der Typ von xmuss float, double oder long double sein.

Verschiedene Anbieter können eine Funktion isnan() enthalten oder nicht.

Die angeblich übertragbare Möglichkeit, nach NaNzu suchen, besteht in der Verwendung der IEEE 754-Eigenschaft, dass NaNnicht mit sich selbst übereinstimmt: d. H. x == x ist falsch, wenn xNaNist.

Die letzte Option funktioniert jedoch möglicherweise nicht mit jedem Compiler und einigen Einstellungen (insbesondere Optimierungseinstellungen), sodass Sie im letzten Fall immer das Bitmuster überprüfen können ...

155
BlueTrin

Es gibt auch eine header-only Bibliothek , die in Boost vorhanden ist und über nette Tools für den Umgang mit Fließkomma-Datentypen verfügt

#include <boost/math/special_functions/fpclassify.hpp>

Sie erhalten folgende Funktionen:

template <class T> bool isfinite(T z);
template <class T> bool isinf(T t);
template <class T> bool isnan(T t);
template <class T> bool isnormal(T t);

Wenn Sie Zeit haben, sehen Sie sich das gesamte Math-Toolkit von Boost an, es hat viele nützliche Werkzeuge und wächst schnell.

Auch beim Umgang mit Floating- und Non-Floating-Punkten kann es sinnvoll sein, die Numeric-Conversions zu betrachten.

82
Anonymous

Es gibt drei "offizielle" Möglichkeiten: posixisnan macro , c ++ 0xisnan Funktionsvorlage oder visual c ++_isnan function .

Leider ist es ziemlich unpraktisch festzustellen, welche davon verwendet werden soll.

Und leider gibt es keine zuverlässige Methode, um festzustellen, ob Sie eine IEEE 754-Darstellung mit NaNs haben. Die Standardbibliothek bietet einen offiziellen Weg (numeric_limits<double>::is_iec559). Aber in der Praxis vermissen Compiler wie g ++ das.

Theoretisch könnte man einfachx != xverwenden, aber Compiler wie g ++ und visual c ++ vermasseln das.

Testen Sie am Ende die spezifischen NaN-Bitmuster , wobei Sie eine bestimmte Repräsentation wie IEEE 754 annehmen (und hoffentlich irgendwann erzwingen!).


EDIT: Als Beispiel für "Compiler wie g ++ ... das verschrauben" betrachten

#include <limits>
#include <assert.h>

void foo( double a, double b )
{
    assert( a != b );
}

int main()
{
    typedef std::numeric_limits<double> Info;
    double const nan1 = Info::quiet_NaN();
    double const nan2 = Info::quiet_NaN();
    foo( nan1, nan2 );
}

Kompilieren mit g ++ (TDM-2 mingw32) 4.4.1:

 C:\test> Typ "C:\Programme\@Befehle\gnuc.bat" 
 @ Rem -finput-charset = windows-1252 
 @ G ++ -O -pedantic -std = c + +98 - Wall -Write-Strings% * -Wno-long-long 

 C:\test> gnuc x.cpp 

 C:\test> ein &&-Echo funktioniert ... | | echo! fehlgeschlagen 
 funktioniert ...

 C:\test> gnuc x.cpp --fast-math 

 C:\test> ein && echo funktioniert ... || echo! failed 
 Die Assertion ist fehlgeschlagen: a! = b, Datei x.cpp, Zeile 6 

 Diese Anwendung hat die Runtime aufgefordert, sie auf ungewöhnliche Weise zu beenden .
 Bitte wenden Sie sich an das Support-Team der Anwendung Weitere Informationen .
! fehlgeschlagen 

 C:\test> _
43

Es gibt ein std :: isnan, wenn der Compiler c99-Erweiterungen unterstützt, aber ich bin nicht sicher, ob Mingw dies tut.

Hier ist eine kleine Funktion, die funktionieren sollte, wenn Ihr Compiler nicht die Standardfunktion hat:

bool custom_isnan(double var)
{
    volatile double d = var;
    return d != d;
}
38
CTT

Sie können numeric_limits<float>::quiet_NaN( ) verwenden, das in der Standardbibliothek limits definiert ist, um mit zu testen. Für double ist eine eigene Konstante definiert.

#include <iostream>
#include <math.h>
#include <limits>

using namespace std;

int main( )
{
   cout << "The quiet NaN for type float is:  "
        << numeric_limits<float>::quiet_NaN( )
        << endl;

   float f_nan = numeric_limits<float>::quiet_NaN();

   if( isnan(f_nan) )
   {
       cout << "Float was Not a Number: " << f_nan << endl;
   }

   return 0;
}

Ich weiß nicht, ob dies auf allen Plattformen funktioniert, da ich nur mit g ++ unter Linux getestet habe.

25
Bill the Lizard

Sie können die Funktion isnan() verwenden, müssen jedoch die mathematische Bibliothek einschließen.

#include <cmath>

Da diese Funktion Teil von C99 ist, ist sie nicht überall verfügbar. Wenn Ihr Lieferant die Funktion nicht zur Verfügung stellt, können Sie auch eine eigene Variante für die Kompatibilität definieren.

inline bool isnan(double x) {
    return x != x;
}
17
raimue

nan Prävention

Meine Antwort auf diese Frage lautet verwende keine rückwirkenden Prüfungen für nan. Verwenden Sie stattdessen Preventive, um nach Abteilungen der Form 0.0/0.0 zu suchen.

#include <float.h>
float x=0.f ;             // I'm gonna divide by x!
if( !x )                  // Wait! Let me check if x is 0
  x = FLT_MIN ;           // oh, since x was 0, i'll just make it really small instead.
float y = 0.f / x ;       // whew, `nan` didn't appear.

nan ergibt sich aus der Operation 0.f/0.f oder 0.0/0.0. nan ist ein schrecklicher Nemesis für die Stabilität Ihres Codes, der erkannt und verhindert sehr sorgfältig erkannt werden muss1. Die Eigenschaften von nan, die sich von normalen Zahlen unterscheiden:

  • nan ist giftig (5 * nan = nan)
  • nan ist nicht gleich irgendetwas, nicht einmal selbst (nan! = nan)
  • nan nicht größer als alles (nan!> 0)
  • nan ist nicht weniger als alles (nan! <0)

Die letzten beiden aufgeführten Eigenschaften sind nicht logisch und führen zu einem ungeraden Verhalten von Code, der sich auf Vergleiche mit einer nan-Nummer stützt (die drittletzte Eigenschaft ist auch ungerade, aber Sie werden x != x ? wahrscheinlich niemals in Ihrem Code sehen (es sei denn Sie.) auf nan (unzuverlässig) prüfen)).

In meinem eigenen Code habe ich festgestellt, dass nan-Werte dazu neigen, Fehler zu finden. (Beachten Sie, dass dies nicht der Fall für inf oder -inf ist. (-inf <0) gibt TRUE zurück, (0 <inf) gibt TRUE zurück, und even (-inf <inf) gibt WAHR zurück , das Verhalten des Codes ist oft immer noch wie gewünscht).

was unter nan zu tun

Was unter 0.0/0.0geschehen soll, muss als Sonderfall behandelt werden, aber was Sie tun, muss von den Zahlen abhängen, die Sie aus dem Code erwarten.

Im obigen Beispiel ist das Ergebnis von (0.f/FLT_MIN) grundsätzlich 0. Möglicherweise möchten Sie, dass 0.0/0.0 stattdessen HUGE generiert. So,

float x=0.f, y=0.f, z;
if( !x && !y )    // 0.f/0.f case
  z = FLT_MAX ;   // biggest float possible
else
  z = y/x ;       // regular division.

Wenn im obigen Beispiel x 0.f wäre, würde sich inf ergeben (was ziemlich gutes/nicht destruktives Verhalten hat, wie oben erwähnt).

Denken Sie daran, dass Ganzzahl Division durch 0 eine Laufzeitausnahme verursacht . Sie müssen also immer nach ganzzahliger Division durch 0 suchen. Nur weil 0.0/0.0 leise zu nan ausgewertet wird, bedeutet das nicht, dass Sie faul sein können und nicht auf 0.0/0.0 prüfen sollten, bevor es passiert.

Prüfungen auf nan über x != x sind manchmal unzuverlässig (x != x wird von einigen optimierenden Compilern entfernt, die die IEEE-Konformität verletzen, insbesondere wenn der -ffast-math-Schalter aktiviert ist).

12
bobobobo

Der folgende Code verwendet die Definition von NAN (alle Exponentenbits gesetzt, mindestens ein gebrochenes Bit gesetzt) ​​und nimmt an, dass sizeof (int) = sizeof (float) = 4. Sie können NAN in der Wikipedia nach Details suchen.

bool IsNan( float value ) { return ((*(UINT*)&value) & 0x7fffffff) > 0x7f800000; }

11
Ian

Ab C++ 14 gibt es eine Reihe von Möglichkeiten, um zu testen, ob eine Gleitkommazahl value eine NaN ist.

Von diesen Möglichkeiten funktioniert nur die Überprüfung der Bits der Zahlendarstellung zuverlässig, wie in meiner ursprünglichen Antwort vermerkt. Insbesondere std::isnan Und das häufig vorgeschlagene Häkchen v != v Funktionieren nicht zuverlässig und sollten nicht verwendet werden, damit Ihr Code nicht ordnungsgemäß funktioniert, wenn jemand entscheidet, dass eine Gleitkommaoptimierung erforderlich ist, und fragt die Compiler, um das zu tun. Diese Situation kann sich ändern, Compiler können anpassungsfähiger werden, aber für dieses Problem, das in den 6 Jahren seit der ursprünglichen Antwort nicht aufgetreten ist.

Für ungefähr 6 Jahre war meine ursprüngliche Antwort die ausgewählte Lösung für diese Frage, die in Ordnung war. Vor kurzem wurde jedoch eine vielbeachtete Antwort ausgewählt, die den unzuverlässigen v != v - Test empfiehlt. Daher diese zusätzliche, aktuellere Antwort (wir haben jetzt die Standards C++ 11 und C++ 14 und C++ 17 in Sicht).


Die wichtigsten Methoden zur Überprüfung der NaN-Aktivität ab C++ 14 sind:

  • std::isnan(value) )
    ist seit C++ 11 die beabsichtigte Standardbibliotheksmethode. isnan steht anscheinend in Konflikt mit dem gleichnamigen Posix-Makro, aber in der Praxis ist dies kein Problem. Das Hauptproblem besteht darin, dass bei Anforderung einer Gleitkomma-Arithmetikoptimierung mit mindestens einem Hauptcompiler, nämlich g ++, std::isnanfalse für das NaN-Argument zurückgibt .

  • (fpclassify(value) == FP_NAN) )
    Leidet unter dem gleichen Problem wie std::isnan, D. H. Ist nicht zuverlässig.

  • (value != value) )
    Empfohlen in vielen SO= Antworten. Leidet unter dem gleichen Problem wie std::isnan, D. H. Ist nicht zuverlässig.

  • (value == Fp_info::quiet_NaN()) )
    Dies ist ein Test, bei dem mit Standardverhalten keine NaNs erkannt werden sollten, bei dem optimierten Verhalten jedoch NaNs erkannt werden könnten (aufgrund des optimierten Codes, der nur die Bitlevel-Darstellungen direkt vergleicht), und der möglicherweise mit einer anderen Methode kombiniert wird, um die zu erfassen Standard nicht optimiertes Verhalten, konnte NaN zuverlässig erkennen. Leider hat es sich als nicht zuverlässig erwiesen.

  • (ilogb(value) == FP_ILOGBNAN) )
    Leidet unter dem gleichen Problem wie std::isnan, D. H. Ist nicht zuverlässig.

  • isunordered(1.2345, value) )
    Leidet unter dem gleichen Problem wie std::isnan, D. H. Ist nicht zuverlässig.

  • is_ieee754_nan( value ) )
    Dies ist keine Standardfunktion. Es prüft die Bits gemäß dem IEEE 754-Standard. Es ist absolut zuverlässig aber der Code ist etwas systemabhängig.


Im folgenden vollständigen Testcode ist "Erfolg", ob ein Ausdruck die Nanheit des Wertes meldet. Für die meisten Ausdrücke entspricht dieses Erfolgsmaß, das Ziel der Erkennung von NaNs und nur von NaNs, ihrer Standardsemantik. Für den Ausdruck (value == Fp_info::quiet_NaN()) ) Ist das Standardverhalten jedoch, dass er nicht als NaN-Detektor funktioniert.

#include <cmath>        // std::isnan, std::fpclassify
#include <iostream>
#include <iomanip>      // std::setw
#include <limits>
#include <limits.h>     // CHAR_BIT
#include <sstream>
#include <stdint.h>     // uint64_t
using namespace std;

#define TEST( x, expr, expected ) \
    [&](){ \
        const auto value = x; \
        const bool result = expr; \
        ostringstream stream; \
        stream << boolalpha << #x " = " << x << ", (" #expr ") = " << result; \
        cout \
            << setw( 60 ) << stream.str() << "  " \
            << (result == expected? "Success" : "FAILED") \
            << endl; \
    }()

#define TEST_ALL_VARIABLES( expression ) \
    TEST( v, expression, true ); \
    TEST( u, expression, false ); \
    TEST( w, expression, false )

using Fp_info = numeric_limits<double>;

inline auto is_ieee754_nan( double const x )
    -> bool
{
    static constexpr bool   is_claimed_ieee754  = Fp_info::is_iec559;
    static constexpr int    n_bits_per_byte     = CHAR_BIT;
    using Byte = unsigned char;

    static_assert( is_claimed_ieee754, "!" );
    static_assert( n_bits_per_byte == 8, "!" );
    static_assert( sizeof( x ) == sizeof( uint64_t ), "!" );

    #ifdef _MSC_VER
        uint64_t const bits = reinterpret_cast<uint64_t const&>( x );
    #else
        Byte bytes[sizeof(x)];
        memcpy( bytes, &x, sizeof( x ) );
        uint64_t int_value;
        memcpy( &int_value, bytes, sizeof( x ) );
        uint64_t const& bits = int_value;
    #endif

    static constexpr uint64_t   sign_mask       = 0x8000000000000000;
    static constexpr uint64_t   exp_mask        = 0x7FF0000000000000;
    static constexpr uint64_t   mantissa_mask   = 0x000FFFFFFFFFFFFF;

    (void) sign_mask;
    return (bits & exp_mask) == exp_mask and (bits & mantissa_mask) != 0;
}

auto main()
    -> int
{
    double const v = Fp_info::quiet_NaN();
    double const u = 3.14;
    double const w = Fp_info::infinity();

    cout << boolalpha << left;
    cout << "Compiler claims IEEE 754 = " << Fp_info::is_iec559 << endl;
    cout << endl;;
    TEST_ALL_VARIABLES( std::isnan(value) );                    cout << endl;
    TEST_ALL_VARIABLES( (fpclassify(value) == FP_NAN) );        cout << endl;
    TEST_ALL_VARIABLES( (value != value) );                     cout << endl;
    TEST_ALL_VARIABLES( (value == Fp_info::quiet_NaN()) );      cout << endl;
    TEST_ALL_VARIABLES( (ilogb(value) == FP_ILOGBNAN) );        cout << endl;
    TEST_ALL_VARIABLES( isunordered(1.2345, value) );           cout << endl;
    TEST_ALL_VARIABLES( is_ieee754_nan( value ) );
}

Ergebnisse mit g ++ (Beachten Sie erneut, dass das Standardverhalten von (value == Fp_info::quiet_NaN()) Darin besteht, dass es nicht als NaN-Detektor funktioniert, sondern hier nur von großem praktischen Interesse ist):

 [C:\my\forums\so\282 (detektiere NaN)] 
> g ++ --version | finde "++"
 g ++ (x86_64-win32-sjlj-rev1, Erstellt von MinGW-W64-Projekt) 6.3.0 
 
 [C:\my\forums\so\282 (NaN erkennen) ] 
> g ++ foo.cpp && a
 Compiler behauptet, IEEE 754 = wahr 
 
 V = nan, (std :: isnan (value)) = wahr Erfolg 
 U = 3.14, (std :: isnan (value)) = false Erfolg 
 w = inf, (std :: isnan (value)) = false Erfolg 
 
 v = nan, ((fpclassify (value) = = 0x0100)) = true Erfolg 
 U = 3.14, ((fpclassify (value) == 0x0100)) = false Erfolg 
 W = inf, ((fpclassify (value) == 0x0100)) = falscher Erfolg 
 
 v = nan, ((Wert! = Wert)) = wahrer Erfolg 
 u = 3.14, ((Wert! = Wert)) = falscher Erfolg 
 w = inf, ((value! = value)) = false Success 
 
 v = nan, ((value == Fp_info :: quiet_NaN ()) = false FAILED 
 u = 3.14, ((value == Fp_info :: quiet_NaN ()) = false Success 
 w = inf, ((value == Fp_info :: quiet_NaN ()) = false Success 
 
 v = nan, ((ilogb (value) == ((int) 0x80000000))) = true Erfolg 
 u = 3.14, ((ilogb (value) == ((int ) 0x80000000))) = falscher Erfolg 
 W = inf, ((ilogb (value) == ((int) 0x80000000)) = falscher Erfolg 
 
 V = nan, (isunordered (1.2345, Wert)) = true Success 
 u = 3.14, (isunordered (1.2345, Wert)) = false Success 
 w = inf, (isunordered (1.2345, Wert)) = false Erfolg 
 
 V = nan, (is_ieee754_nan (Wert)) = true Erfolg 
 U = 3.14, (is_ieee754_nan (Wert)) = false Erfolg 
 W = inf , (is_ieee754_nan (value)) = false Success 
 
 [C:\my\forums\so\282 (detect NaN)] 
> g ++ foo.cpp -ffast-math && a
 Compiler behauptet IEEE 754 = true 
 
 V = nan, (std :: isnan (value)) = false FAILED 
 U = 3.14, (std :: isnan (value)) = false Erfolg 
 w = inf, (std :: isnan (value)) = false Erfolg 
 
 v = nan, ((fpclassify (value) = = 0x0100)) = false FAILED 
 U = 3.14, ((fpclassify (value) == 0x0100)) = false Success 
 W = inf, ((fpclassify (value) == 0x0100)) = falscher Erfolg 
 
 v = nan, ((value! = value)) = false FAILED 
 u = 3.14, ((value! = value)) = falscher Erfolg 
 w = inf, ((value! = value)) = false Erfolg 
 
 v = nan, ((value == Fp_info :: quiet_NaN ()) = true Erfolg 
 u = 3.14, ((value == Fp_info :: quiet_NaN ()) = true FAILED 
 w = inf, ((value == Fp_info :: quiet_NaN ()) = true FAILED 
 
 v = nan, ((ilogb (value) == ((int) 0x80000000)) = true Erfolg 
 u = 3.14, ((ilogb (value) == ((int) 0x80000000)) ) = falscher Erfolg 
 w = inf, ((ilogb (value) == ((int) 0x80000000)) = falscher Erfolg 
 
 v = nan, (isunordered (1.2345 , value)) = false FAILED 
 u = 3.14, (isunordered (1.2345, value)) = false Success 
 w = inf, (isunordered (1.2345, value)) = false Success 
 
 v = nan, (is_ieee754_nan (value)) = true Erfolg 
 u = 3.14, (is_ieee754_nan (value)) = false Erfolg 
 w = inf, (is_ieee754_nan ( value)) = false Success 
 
 [C:\my\forums\so\282 (Detect NaN)] 
> _ 

Ergebnisse mit Visual C++:

 [C:\my\forums\so\282 (detektiere NaN)] 
> cl/nologo- 2> & 1 | finde "++"
 Microsoft® C/C++ Optimizing Compiler Version 19.00.23725 für x86 
 
 [C:\my\forums\so\282 (NaN erkennen)] 
> cl foo.cpp/Feb && b
 foo.cpp 
 Compiler behauptet, IEEE 754 = wahr 
 
 v = nan, (std :: isnan (value)) = wahr Erfolg 
 u = 3,14, (std :: isnan (Wert)) = falscher Erfolg 
 w = inf, (std :: isnan (Wert)) = falscher Erfolg 
 
 v = nan , ((fpclassify (value) == 2)) = true Success 
 u = 3.14, ((fpclassify (value) == 2)) = false Success 
 w = inf, ((fpclassify.) (value) == 2)) = false Erfolg 
 
 v = nan, ((value! = value)) = true Erfolg 
 u = 3.14, ((value! = value)) = false Success 
 w = inf, ((value! = value)) = false Success 
 
 v = nan, ((value == Fp_info :: quiet_NaN ( ))) = false FAILED 
 u = 3.14, ((value == Fp_info :: quiet_NaN ()) = false Success 
 w = inf, ((value == Fp_info :: quiet_NaN ( ))) = false Erfolg 
 
 V = nan, ((ilogb (value) == 0x7fffffff)) = true Erfolg 
 U = 3.14, ((ilogb (value) == 0x7fffffff) = false Success 
 w = inf, ((ilogb (value) == 0x7fffffff)) = true FAILED 
 
 v = nan, (isunordered (1.2345, value)) = true Success 
 u = 3,14, (ungeordnet (1,2345, Wert)) = falscher Erfolg 
 w = inf, (ungeordnet (1,2345, Wert)) = falscher Erfolg 
 
 v = nan, (is_ieee754_nan (value)) = true Erfolg 
 u = 3.14, (is_ieee754_nan (value)) = false Erfolg 
 w = inf, (is_ieee754_nan (value)) = false Erfolg 
 
 [C:\my\forums\so\282 (detektiere NaN)] 
> cl foo.cpp/Feb/fp: schnell && b
 foo.cpp 
 Compiler behauptet, IEEE 754 = wahr 
 
 v = nan, (std :: isnan (value)) = wahr Erfolg 
 u = 3,14, (std :: isnan (Wert)) = falscher Erfolg 
 w = inf, (std :: isnan (Wert)) = falscher Erfolg 
 
 v = nan , ((fpclassify (value) == 2)) = true Success 
 u = 3.14, ((fpclassify (value) == 2)) = false Success 
 w = inf, ((fpclassify.) (value) == 2)) = false Erfolg 
 
 v = nan, ((value! = value)) = true Erfolg 
 u = 3.14, ((value! = value)) = false Success 
 w = inf, ((value! = value)) = false Success 
 
 v = nan, ((value == Fp_info :: quiet_NaN ( ))) = false FAILED 
 u = 3.14, ((value == Fp_info :: quiet_NaN ()) = false Success 
 w = inf, ((value == Fp_info :: quiet_NaN ( ))) = false Erfolg 
 
 V = nan, ((ilogb (value) == 0x7fffffff)) = true Erfolg 
 U = 3.14, ((ilogb (value) == 0x7fffffff) = false Success 
 w = inf, ((ilogb (value) == 0x7fffffff)) = true FAILED 
 
 v = nan, (isunordered (1.2345, value)) = true Success 
 u = 3,14, (ungeordnet (1,2345, Wert)) = falscher Erfolg 
 w = inf, (ungeordnet (1,2345, Wert)) = falscher Erfolg 
 
 v = nan, (is_ieee754_nan (value)) = true Erfolg 
 u = 3.14, (is_ieee754_nan (value)) = false Erfolg 
 w = inf, (is_ieee754_nan (value)) = false Erfolg 
 
 [C:\my\forums\so\282 (detektiere NaN)] 
> _ 

Zusammenfassend hat nur das direkte Testen der Darstellung auf Bitebene mit der in diesem Testprogramm definierten Funktion is_ieee754_nan In allen Fällen sowohl mit g ++ als auch mit Visual C++ zuverlässig funktioniert.


Nachtrag:
Nachdem ich das oben Gesagte gepostet hatte, wurde ich auf eine weitere Möglichkeit aufmerksam, NaN zu testen, die in einer weiteren Antwort hier erwähnt wird, nämlich ((value < 0) == (value >= 0)). Es stellte sich heraus, dass das mit Visual C++ gut funktionierte, aber mit der Option -ffast-math Von g ++ fehlschlug. Nur das direkte Testen von Bitmustern funktioniert zuverlässig.

inline bool IsNan(float f)
{
    const uint32 u = *(uint32*)&f;
    return (u&0x7F800000) == 0x7F800000 && (u&0x7FFFFF);    // Both NaN and qNan.
}

inline bool IsNan(double d)
{
    const uint64 u = *(uint64*)&d;
    return (u&0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && (u&0xFFFFFFFFFFFFFULL);
}

Dies funktioniert, wenn sizeof(int) 4 und sizeof(long long) 8 ist.

Während der Laufzeit ist es nur ein Vergleich, Gussteile brauchen keine Zeit. Es ändert lediglich die Konfiguration der Vergleichsflags, um die Gleichheit zu prüfen.

7
ST3

Nachdem ich die anderen Antworten gelesen hatte, wollte ich etwas, das die Warnung bezüglich des Fließkommavergleichs durchläuft und unter schneller Berechnung nicht kaputt geht. Der folgende Code scheint zu funktionieren:

/*
  Portable warning-free NaN test:
    * Does not emit warning with -Wfloat-equal (does not use float comparisons)
    * Works with -O3 -ffast-math (floating-point optimization)
    * Only call to standard library is memset and memcmp via <cstring>
    * Works for IEEE 754 compliant floating-point representations
    * Also works for extended precision long double
*/

#include <cstring>
template <class T> bool isNaN(T x)
{
  /*Initialize all bits including those used for alignment to zero. This sets
  all the values to positive zero but does not clue fast math optimizations as
  to the value of the variables.*/
  T z[4];
  memset(z, 0, sizeof(z));
  z[1] = -z[0];
  z[2] = x;
  z[3] = z[0] / z[2];

  /*Rationale for following test:
    * x is 0 or -0                                --> z[2] = 0, z[3] = NaN
    * x is a negative or positive number          --> z[3] = 0
    * x is a negative or positive denormal number --> z[3] = 0
    * x is negative or positive infinity          --> z[3] = 0
      (IEEE 754 guarantees that 0 / inf is zero)
    * x is a NaN                                  --> z[3] = NaN != 0.
  */

  //Do a bitwise comparison test for positive and negative zero.
  bool z2IsZero = memcmp(&z[2], &z[0], sizeof(T)) == 0 ||
                  memcmp(&z[2], &z[1], sizeof(T)) == 0;

  bool z3IsZero = memcmp(&z[3], &z[0], sizeof(T)) == 0 ||
                  memcmp(&z[3], &z[1], sizeof(T)) == 0; 

  //If the input is bitwise zero or negative zero, then it is not NaN.
  return !z2IsZero && !z3IsZero;
}

//NaN test suite
#include <iostream>

/*If printNaN is true then only expressions that are detected as NaN print and
vice versa.*/
template <class T> void test(bool printNaN)
{
  T v[10] = {-0.0, 0.0, -1.0, 1.0,
    std::numeric_limits<T>::infinity(),
    -std::numeric_limits<T>::infinity(),
    std::numeric_limits<T>::denorm_min(),
    -std::numeric_limits<T>::denorm_min(),
    std::numeric_limits<T>::quiet_NaN(),
    std::numeric_limits<T>::signaling_NaN()};
  for(int i = 0; i < 10; i++)
  {
    for(int j = 0; j < 10; j++)
    {
      if(isNaN(v[i] + v[j]) == printNaN)
        std::cout << v[i] << "+" << v[j] << " = " << v[i] + v[j] << std::endl;
      if(isNaN(v[i] - v[j]) == printNaN)
        std::cout << v[i] << "-" << v[j] << " = " << v[i] - v[j] << std::endl;
      if(isNaN(v[i] * v[j]) == printNaN)
        std::cout << v[i] << "*" << v[j] << " = " << v[i] * v[j] << std::endl;
      if(isNaN(v[i] / v[j]) == printNaN)
        std::cout << v[i] << "/" << v[j] << " = " << v[i] / v[j] << std::endl;
    }
  }
}

//Test each floating-point type.
int main()
{
  std::cout << "NaNs:" << std::endl;
  test<float>(true);
  test<double>(true);
  test<long double>(true);
  std::cout << std::endl << "Not NaNs:" << std::endl;
  test<float>(false);
  test<double>(false);
  test<long double>(false);
  return 0;
}

Für mich könnte die Lösung ein Makro sein, um es explizit inline und damit schnell genug zu machen. Sie beruht auf der Tatsache, dass der einzige Fall, wenn ein Wert nicht gleich ist, der Fall ist, wenn der Wert keine Zahl ist.

#ifndef isnan
  #define isnan(a) (a != a)
#endif
4
user1705817

Eine mögliche Lösung, die nicht von der spezifischen IEEE-Darstellung für NaN abhängen würde, wäre folgende:

template<class T>
bool isnan( T f ) {
    T _nan =  (T)0.0/(T)0.0;
    return 0 == memcmp( (void*)&f, (void*)&_nan, sizeof(T) );
}
4
Dan Nathan

In Anbetracht dessen, dass (x! = X) nicht immer für NaN garantiert ist (wenn Sie beispielsweise die Option -ffast-math verwenden), habe ich Folgendes verwendet:

#define IS_NAN(x) (((x) < 0) == ((x) >= 0))

Zahlen können nicht gleichzeitig <0 und> = 0 sein, daher besteht diese Prüfung nur dann, wenn die Anzahl weder kleiner noch gleich Null ist. Welches ist im Grunde keine Zahl oder NaN.

Sie können dies auch verwenden, wenn Sie bevorzugen:

#define IS_NAN(x) (!((x)<0) && !((x)>=0)

Ich bin nicht sicher, wie dies von -ffast-math beeinflusst wird, daher kann Ihre Laufleistung variieren.

4
Jerramy

Das funktioniert:

#include <iostream>
#include <math.h>
using namespace std;

int main ()
{
  char ch='a';
  double val = nan(&ch);
  if(isnan(val))
     cout << "isnan" << endl;

  return 0;
}

ausgabe: isnan

3
edW

Es scheint mir, dass der beste wirklich plattformübergreifende Ansatz darin besteht, eine Union zu verwenden und das Bitmuster des Double zu testen, um nach NaNs zu suchen. 

Ich habe diese Lösung nicht gründlich getestet, und es gibt möglicherweise eine effizientere Art, mit den Bitmustern zu arbeiten, aber ich denke, dass es funktionieren sollte.

#include <stdint.h>
#include <stdio.h>

union NaN
{
    uint64_t bits;
    double num;
};

int main()
{
    //Test if a double is NaN
    double d = 0.0 / 0.0;
    union NaN n;
    n.num = d;
    if((n.bits | 0x800FFFFFFFFFFFFF) == 0xFFFFFFFFFFFFFFFF)
    {
        printf("NaN: %f", d);
    }

    return 0;
}
1
Sheldon Juncker

Der IEEE-Standard sagt __., Wenn der Exponent alle 1s, __. Und __. Mantisse nicht Null ist Die Zahl ist eine NaN . Double ist 1 Vorzeichenbit, 11 Exponentenbits und 52 Mantissenbits. Mach ein bisschen nach.

0
bop

Dies erkennt Unendlich und auch NaN in Visual Studio, indem geprüft wird, dass es sich innerhalb der doppelten Grenzen befindet:

//#include <float.h>
double x, y = -1.1; x = sqrt(y);
if (x >= DBL_MIN && x <= DBL_MAX )
    cout << "DETECTOR-2 of errors FAILS" << endl;
else
    cout << "DETECTOR-2 of errors OK" << endl;
0
mathengineer