Sprawdzanie, czy double (lub float) to NaN w C++

Czy istnieje funkcja isnan ()?

PS.: I ' m in MinGW (if that makes a difference).

Rozwiązałem to używając isnan() z <math.h>, która nie istnieje w <cmath>, którą na początku byłem #include.

 328
Author: Peter Mortensen, 2009-02-20

20 answers

Zgodnie ze STANDARDEM IEEE, wartości NaN mają tę dziwną właściwość, że porównania z nimi są Zawsze false. Oznacza to, że dla zmiennoprzecinkowego f, f != f będzie true tylko Jeśli f jest NaN.

Zauważ, że jak zauważyły niektóre komentarze poniżej, nie wszystkie Kompilatory przestrzegają tego przy optymalizacji kodu.

Dla każdego kompilatora, który twierdzi, że używa zmiennoprzecinkowego IEEE, ta sztuczka powinna zadziałać. Ale nie mogę zagwarantować, że to zadziała w praktyce. Sprawdź z Twój kompilator, jeśli masz wątpliwości.

 317
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-26 16:28:20

Nie ma funkcji isnan() dostępnej w bieżącej bibliotece standardowej C++. Została wprowadzona w C99 i zdefiniowana jako makro, a nie Funkcja. Elementy biblioteki standardowej zdefiniowane przez C99 nie są częścią aktualnego standardu C++ ISO/IEC 14882: 1998 ani jego aktualizacji ISO / IEC 14882: 2003.

W 2005 r. zaproponowano Sprawozdanie techniczne nr 1. Tr1 wprowadza kompatybilność z C99 do C++. Pomimo faktu, że nigdy nie został oficjalnie przyjęty do standardu C++, wiele (GCC 4.0+ lub Visual C++ 9.0+ implementacje C++ zapewniają funkcje TR1, wszystkie z nich lub tylko niektóre (Visual C++ 9.0 nie dostarcza funkcji matematycznych C99).

Jeśli tr1 jest dostępny, to cmath zawiera elementy C99 takie jakisnan(), isfinite(), itd. ale są one definiowane jako funkcje, a nie makra, zwykle w przestrzeni nazw std::tr1::, chociaż wiele implementacji (np. GCC 4+ na Linuksie lub w XCode na Mac OS X 10.5+) wstrzykuje je bezpośrednio do std::, więc std::isnan jest dobrze zdefiniowany.

Co więcej, niektóre implementacje C++ nadal udostępniają makro C99 isnan() dla C++ (dołączone przez cmath lub math.h), co może powodować więcej nieporozumień i programiści mogą założyć, że jest to standardowe zachowanie.

Uwaga o Viusal C++, jak wspomniano powyżej, nie dostarcza std::isnan ani std::tr1::isnan, ale dostarcza funkcję rozszerzenia zdefiniowaną jako _isnan(), która jest dostępna od Visual C++ 6.0

Na XCode jest jeszcze więcej zabawy. Jak wspomniano, GCC 4 + definiuje std::isnan. Dla starszych wersji kompilatora i biblioteki Xcode, wydaje się (tutaj istotna dyskusja ), nie miałem okazji sprawdzić) dwie funkcje są zdefiniowane, {[14] } na Intel i __isnand() NA Power PC.

 206
Author: mloskot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-23 16:19:05

Pierwsze rozwiązanie: jeśli używasz C++11

Ponieważ zapytano o to, pojawiło się trochę nowych rozwiązań: ważne jest, aby wiedzieć, że std::isnan() jest częścią C++11

Synopsis

Zdefiniowane w nagłówku <cmath>

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

Określa, czy podana liczba zmiennoprzecinkowa arg nie jest liczbą a (NaN).

Parametry

arg: wartość zmiennoprzecinkowa

Return value

true jeśli arg jest NaN, false inaczej

Numer referencyjny

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

Zwróć uwagę, że jest to niezgodne z-fast-math, jeśli używasz g++, zobacz poniżej inne sugestie.


Inne rozwiązania: jeśli używasz narzędzi niezgodnych z C++11

Dla C99, w C, jest to zaimplementowane jako makro isnan(c), które zwraca wartość int. Typ x jest zmiennoprzecinkowy, podwójny lub długi podwójny.

[[18]}różni sprzedawcy mogą lub może nie zawierać lub nie zawierać funkcji isnan().

Rzekomo przenośnym sposobem sprawdzania NaN jest użycie właściwości IEEE 754, która NaN nie jest sobie równa: tzn. x == x będzie fałszywa dla x jako NaN.

Ostatnia opcja może jednak nie działać z każdym kompilatorem i niektórymi ustawieniami( szczególnie ustawieniami optymalizacji), więc w ostateczności zawsze można sprawdzić wzorzec bitowy ...

 133
Author: BlueTrin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-10 18:13:18

W Boost istnieje również biblioteka tylko nagłówka , która ma schludne narzędzia do obsługi zmiennoprzecinkowych typów danych

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

Otrzymujesz następujące funkcje:

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);

Jeśli masz czas, spójrz na cały zestaw narzędzi matematycznych z Boost, ma wiele przydatnych narzędzi i szybko rośnie.

Również w przypadku punktów zmiennoprzecinkowych i nieprzecinkowych dobrym pomysłem może być przyjrzenie się Konwersjom liczbowym .

 81
Author: Anonymous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-22 18:52:22

Istnieją trzy "oficjalne" sposoby: posix isnan makro , c++0x isnan function template , lub visual c++ _isnan function .

Niestety jest to raczej niepraktyczne, aby wykryć, które z nich użyć.

I niestety, nie ma niezawodnego sposobu, aby wykryć, czy masz reprezentację IEEE 754 z Nan. Biblioteka standardowa oferuje oficjalny taki sposób (numeric_limits<double>::is_iec559). Ale w praktyce Kompilatory takie jak g++ to psują.

Teoretycznie można by użyć po prostu x != x, ale Kompilatory takie jak g++ i visual c++ to psują.

Więc w końcu, test na konkretne NaN bitpatterns , zakładając (i miejmy nadzieję, egzekwowanie, w pewnym momencie!) szczególną reprezentację, np. IEEE 754.


EDIT : jako przykład "kompilatorów takich jak g++ ... screw that up", rozważ

#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 );
}

Kompilowanie z g++ (TDM-2 mingw32) 4.4.1:

C:\test> type "C:\Program Files\@commands\gnuc.bat"
@rem -finput-charset=windows-1252
@g++ -O -pedantic -std=c++98 -Wall -Wwrite-strings %* -Wno-long-long

C:\test> gnuc x.cpp

C:\test> a && echo works... || echo !failed
works...

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

C:\test> a && echo works... || echo !failed
Assertion failed: a != b, file x.cpp, line 6

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
!failed

C:\test> _
 42
Author: Cheers and hth. - Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-07 21:00:58

Istnieje STD:: isnan, jeśli kompilator obsługuje rozszerzenia c99, ale nie jestem pewien, czy MinGW tak.

Oto mała funkcja, która powinna działać, jeśli kompilator nie ma standardowej funkcji:

bool custom_isnan(double var)
{
    volatile double d = var;
    return d != d;
}
 38
Author: CTT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-20 18:14:58

Możesz użyć numeric_limits<float>::quiet_NaN( ) zdefiniowanego w bibliotece standardowej limits do testowania. Istnieje osobna stała zdefiniowana dla double.

#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;
}

Nie wiem, czy to działa na wszystkich platformach, ponieważ testowałem tylko z g++ na Linuksie.

 25
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-20 19:18:12

Możesz użyć funkcji isnan(), ale musisz dołączyć bibliotekę matematyki C.

#include <cmath>

Ponieważ ta funkcja jest częścią C99, nie jest dostępna wszędzie. Jeśli twój dostawca nie dostarczy tej funkcji, możesz również zdefiniować swój własny wariant zgodności.

inline bool isnan(double x) {
    return x != x;
}
 17
Author: raimue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-07 09:34:32

Nan prevention

Moja odpowiedź na to pytanie brzmi nie używaj kontroli wstecznych dla nan. prewencyjne sprawdzanie podziałów formularza 0.0/0.0 zamiast tego.

#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 wyniki operacji 0.f/0.f lub 0.0/0.0. nan jest strasznym nemezis do stabilności kodu, który musi być wykryty i zapobiec bardzo ostrożnie1. Właściwości nan, które różnią się od normalnych liczby:

  • nan jest toksyczny, (5*nan=nan)
  • nan nie jest równa niczym, nawet sobie (nan!= nan)
  • nan nie większy niż cokolwiek (nan !> 0)
  • nan jest nie mniej niż cokolwiek (nan !

Ostatnie 2 właściwości są przeciwnormatywne i spowodują dziwne zachowanie kodu, które opiera się na porównaniu z liczbą nan (3. ostatnia właściwość jest nieparzysta, ale prawdopodobnie nigdy nie zobaczysz x != x ? w Twój kod (chyba że sprawdzasz nan (nierzetelnie))).

W moim własnym kodzie, zauważyłem, że {[2] } wartości zwykle wytwarzają trudne do znalezienia błędy. (Zauważ, że jest to , a nie przypadek inf lub -inf. (-inf TRUE, ( 0 inf ) zwraca TRUE, a nawet (-inf inf) zwraca TRUE. Więc, z mojego doświadczenia, zachowanie kodu jest często {[55] } nadal zgodnie z życzeniem).

Co robić pod nan

What you want to happen under 0.0/0.0 musi być traktowany jako specjalny przypadek , ale to, co robisz, musi zależeć od liczb, które spodziewasz się wyjść z kodu.

W powyższym przykładzie, wynikiem (0.f/FLT_MIN) będzie 0, W zasadzie. Możesz zamiast tego chcieć 0.0/0.0 wygenerować HUGE.

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.

Tak więc w powyższym przypadku, gdyby x było 0.f, inf wynikałoby (co ma całkiem dobre/nieniszczące zachowanie, jak wspomniano powyżej).

Remember, integer dzielenie przez 0 powoduje runtime wyjątek . Więc zawsze musisz sprawdzić podział liczby całkowitej przez 0. To, że 0.0/0.0 po cichu ocenia na nan, nie oznacza, że możesz być leniwy i nie sprawdzać 0.0/0.0, zanim to się stanie.

1 sprawdzanie nan przez x != x jest czasami zawodne (x != x jest usuwane przez niektóre Kompilatory optymalizujące, które łamią zgodność z IEEE, szczególnie gdy włączony jest przełącznik -ffast-math).

 13
Author: bobobobo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:05

Poniższy kod używa definicji NAN (zbiór wszystkich bitów wykładniczych, co najmniej jeden zestaw bitów ułamkowych) i zakłada, że sizeof(int) = sizeof(float) = 4. Możesz poszukać NAN w Wikipedii po szczegóły.

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

 11
Author: Ian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-05 01:53:33
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);
}

To działa, Jeśli sizeof(int) jest 4 i {[2] } jest 8.

W czasie pracy jest to tylko porównanie, odlewy nie zajmują czasu. Po prostu zmienia konfigurację FLAG porównawczych, aby sprawdzić równość.

 7
Author: ST3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-19 21:56:13

W C++14 istnieje wiele sposobów na sprawdzenie, czy Liczba zmiennoprzecinkowa value jest NaN.

Z TYCH SPOSOBÓW, tylko sprawdzanie bitów reprezentacji liczby, działa niezawodnie, jak zaznaczono w mojej pierwotnej odpowiedzi. W szczególności std::isnan i często proponowane sprawdzenie v != v nie działają niezawodnie i nie powinny być używane, aby Twój kod nie przestał działać poprawnie, gdy ktoś zdecyduje, że optymalizacja zmiennoprzecinkowa jest potrzebna i poprosi kompilator o to. Ta sytuacja może się zmienić, Kompilatory mogą uzyskać bardziej zgodne, ale dla tego problemu, który nie wystąpił w ciągu 6 lat od pierwotnej odpowiedzi.

Przez około 6 lat moją pierwotną odpowiedzią było wybrane rozwiązanie tego pytania, które było OK. Ale ostatnio wybrano bardzo upvoted odpowiedź zalecającą niewiarygodne v != v test został wybrany. Stąd ta dodatkowa, bardziej aktualna odpowiedź (obecnie mamy na horyzoncie standardy C++11 I C++14 oraz C++17).


Główne sposoby sprawdzania NaN-ness, od C++14, to:

  • std::isnan(value) )
    jest zamierzoną biblioteką standardową od C++11. isnan najwyraźniej koliduje z Makro Posix o tej samej nazwie, ale w praktyce nie stanowi to problemu. Głównym problemem jest że gdy wymagana jest optymalizacja arytmetyczna zmiennoprzecinkowa, to z co najmniej jednym głównym kompilatorem, a mianowicie g++, std::isnan zwraca false dla argumentu NaN .

  • (fpclassify(value) == FP_NAN) )
    Cierpi na ten sam problem co std::isnan, tzn. nie jest niezawodny.

  • (value != value) )
    Polecane w wielu Tak odpowiedzi. Cierpi na ten sam problem co std::isnan, czyli, nie jest wiarygodny.

  • (value == Fp_info::quiet_NaN()) )
    Jest to test, który przy standardowym zachowaniu nie powinien wykrywać Nan, ale z zoptymalizowane zachowanie może wykrywać Nan (ze względu na zoptymalizowany kod porównujący bitlevel bezpośrednio), a być może w połączeniu z innym sposobem na obejmuje standardowe Nie zoptymalizowane zachowanie, może niezawodnie wykryć NaN. Niestety okazało się, że nie działa niezawodnie.

  • (ilogb(value) == FP_ILOGBNAN) )
    [4]}, tzn. nie jest wiarygodny.

  • isunordered(1.2345, value) )
    [4]}, tzn. nie jest wiarygodny.

  • is_ieee754_nan( value ) )
    To nie jest standardowa funkcja. Sprawdza bity zgodnie z IEEE 754 standard. Jest całkowicie niezawodny , ale kod jest w pewnym stopniu zależny od systemu.


W poniższy kompletny kod testowy "success" określa, czy wyrażenie zgłasza Nan-ness wartości. Dla większości wyrażeń ta miara sukcesu, cel wykrywania Nan i tylko Nan, odpowiada ich standardowej semantyce. W przypadku wyrażenia (value == Fp_info::quiet_NaN()) ) standardowym zachowaniem jest jednak to, że nie działa ono jako detektor NaN.

#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 ) );
}

Wyniki z g++ (zauważ jeszcze raz, że standardowe zachowanie (value == Fp_info::quiet_NaN()) jest takie, że nie działa on jako detektor NaN, jest po prostu bardzo praktyczny zainteresowanie tutaj):

[C:\my\forums\so\282  (detect NaN)]
> g++ --version | find "++"
g++ (x86_64-win32-sjlj-rev1, Built by MinGW-W64 project) 6.3.0

[C:\my\forums\so\282  (detect NaN)]
> g++ foo.cpp && a
Compiler claims IEEE 754 = true

v = nan, (std::isnan(value)) = true                           Success
u = 3.14, (std::isnan(value)) = false                         Success
w = inf, (std::isnan(value)) = false                          Success

v = nan, ((fpclassify(value) == 0x0100)) = true               Success
u = 3.14, ((fpclassify(value) == 0x0100)) = false             Success
w = inf, ((fpclassify(value) == 0x0100)) = false              Success

v = nan, ((value != value)) = true                            Success
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            Success

v = nan, ((ilogb(value) == ((int)0x80000000))) = true         Success
u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false       Success
w = inf, ((ilogb(value) == ((int)0x80000000))) = false        Success

v = nan, (isunordered(1.2345, value)) = true                  Success
u = 3.14, (isunordered(1.2345, value)) = false                Success
w = inf, (isunordered(1.2345, value)) = false                 Success

v = nan, (is_ieee754_nan( value )) = true                     Success
u = 3.14, (is_ieee754_nan( value )) = false                   Success
w = inf, (is_ieee754_nan( value )) = false                    Success

[C:\my\forums\so\282  (detect NaN)]
> g++ foo.cpp -ffast-math && a
Compiler claims IEEE 754 = true

v = nan, (std::isnan(value)) = false                          FAILED
u = 3.14, (std::isnan(value)) = false                         Success
w = inf, (std::isnan(value)) = false                          Success

v = nan, ((fpclassify(value) == 0x0100)) = false              FAILED
u = 3.14, ((fpclassify(value) == 0x0100)) = false             Success
w = inf, ((fpclassify(value) == 0x0100)) = false              Success

v = nan, ((value != value)) = false                           FAILED
u = 3.14, ((value != value)) = false                          Success
w = inf, ((value != value)) = false                           Success

v = nan, ((value == Fp_info::quiet_NaN())) = true             Success
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         Success
u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false       Success
w = inf, ((ilogb(value) == ((int)0x80000000))) = false        Success

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                     Success
u = 3.14, (is_ieee754_nan( value )) = false                   Success
w = inf, (is_ieee754_nan( value )) = false                    Success

[C:\my\forums\so\282  (detect NaN)]
> _

Wyniki z Visual C++:

[C:\my\forums\so\282  (detect NaN)]
> cl /nologo- 2>&1 | find "++"
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23725 for x86

[C:\my\forums\so\282  (detect NaN)]
> cl foo.cpp /Feb && b
foo.cpp
Compiler claims IEEE 754 = true

v = nan, (std::isnan(value)) = true                           Success
u = 3.14, (std::isnan(value)) = false                         Success
w = inf, (std::isnan(value)) = false                          Success

v = nan, ((fpclassify(value) == 2)) = true                    Success
u = 3.14, ((fpclassify(value) == 2)) = false                  Success
w = inf, ((fpclassify(value) == 2)) = false                   Success

v = nan, ((value != value)) = true                            Success
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            Success

v = nan, ((ilogb(value) == 0x7fffffff)) = true                Success
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, (isunordered(1.2345, value)) = false                Success
w = inf, (isunordered(1.2345, value)) = false                 Success

v = nan, (is_ieee754_nan( value )) = true                     Success
u = 3.14, (is_ieee754_nan( value )) = false                   Success
w = inf, (is_ieee754_nan( value )) = false                    Success

[C:\my\forums\so\282  (detect NaN)]
> cl foo.cpp /Feb /fp:fast && b
foo.cpp
Compiler claims IEEE 754 = true

v = nan, (std::isnan(value)) = true                           Success
u = 3.14, (std::isnan(value)) = false                         Success
w = inf, (std::isnan(value)) = false                          Success

v = nan, ((fpclassify(value) == 2)) = true                    Success
u = 3.14, ((fpclassify(value) == 2)) = false                  Success
w = inf, ((fpclassify(value) == 2)) = false                   Success

v = nan, ((value != value)) = true                            Success
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            Success

v = nan, ((ilogb(value) == 0x7fffffff)) = true                Success
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, (isunordered(1.2345, value)) = false                Success
w = inf, (isunordered(1.2345, value)) = false                 Success

v = nan, (is_ieee754_nan( value )) = true                     Success
u = 3.14, (is_ieee754_nan( value )) = false                   Success
w = inf, (is_ieee754_nan( value )) = false                    Success

[C:\my\forums\so\282  (detect NaN)]
> _

Podsumowując powyższe wyniki, tylko bezpośrednie testowanie reprezentacji na poziomie bitowym, przy użyciu funkcji is_ieee754_nan zdefiniowanej w tym programie testowym, działało niezawodnie we wszystkich przypadkach zarówno z g++ , jak i Visual C++.


Dodatek:
Po opublikowaniu powyższego dowiedziałem się o jeszcze innej możliwej do przetestowania dla NaN, wymienionej w innej odpowiedzi tutaj, a mianowicie ((value < 0) == (value >= 0)). Okazało się, że działa dobrze z wizualnym C++ , ale nie udało się z opcją -ffast-math g++. Tylko bezpośrednie testowanie bitpattern działa niezawodnie.

 6
Author: Cheers and hth. - Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:05

Możliwe rozwiązanie, które nie zależałoby od konkretnej reprezentacji IEEE dla Nan, byłoby następujące:

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
Author: Dan Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-03 22:03:16

Jak dla mnie rozwiązaniem może być makro, aby było wyraźnie inline, a tym samym wystarczająco szybkie. Działa również dla każdego typu float. Opiera się na fakcie, że jedynym przypadkiem, gdy wartość nie jest równa sama w sobie, jest wtedy, gdy wartość nie jest liczbą.

#ifndef isnan
  #define isnan(a) (a != a)
#endif
 4
Author: user1705817,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-11 09:08:56

Po przeczytaniu innych odpowiedzi chciałem czegoś, co przejdzie przez ostrzeżenie o porównywaniu zmiennoprzecinkowym i nie złamie się pod szybką matematyką. Następujący kod wydaje się działać:

/*
  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;
}
 4
Author: William Andrew Burnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-07 07:05:57

Biorąc pod uwagę ,że (x != x) nie zawsze jest gwarantowane dla NaN( np. jeśli używam opcji-ffast-math), używam:

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

Liczby nie mogą być zarówno = 0, więc tak naprawdę ta kontrola przechodzi tylko wtedy, gdy liczba nie jest ani mniejsza, ani większa, ani równa zeru. Co w zasadzie nie ma numeru, albo NaN.

Możesz również użyć tego, jeśli wolisz:

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

Nie jestem pewien, jak to wpływa na-ffast-math, więc twój przebieg może się różnić.

 4
Author: Jerramy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-26 01:06:53

To działa:

#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;
}

Wyjście: isnan

 3
Author: edW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-03 22:38:29

Wydaje mi się, że najlepszym prawdziwie wieloplatformowym podejściem byłoby użycie Unii i przetestowanie wzorca bitowego sobowtóra w celu sprawdzenia Nan.

Nie testowałem dokładnie tego rozwiązania i może istnieje bardziej efektywny sposób pracy z wzorcami bitowymi, ale myślę, że powinno zadziałać.

#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
Author: Sheldon Juncker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-08 17:20:07

Standard IEEE mówi gdy wykładnik jest wszystkie 1s oraz mantissa nie jest zerem, numer to NaN. Double to 1 bit znakowy, 11 bitów wykładniczych i 52 bity mantysy. Sprawdź trochę.

 0
Author: bop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-31 19:26:31

Jako komentarze powyżej stan a != a nie będzie działać w G++ i niektórych innych kompilatorach, ale ta sztuczka powinna. Może nie jest tak skuteczny, ale i tak jest sposób:

bool IsNan(float a)
{
    char s[4];
    sprintf(s, "%.3f", a);
    if (s[0]=='n') return true;
    else return false;
}

Zasadniczo, w g++ (nie jestem pewien co do innych) printf wypisuje 'nan' na %d lub %.formatuje f, jeśli zmienna nie jest poprawną liczbą całkowitą / zmienną zmienną. Dlatego ten kod sprawdza, czy pierwszy znak łańcucha jest " n " (jak w "nan")

 -3
Author: ZenJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-26 21:33:59