web-dev-qa-db-ja.com

C ++でdouble(またはfloat)がNaNかどうかを調べる

Isnan()関数はありますか?

シモンズ:私は MinGW にいる(それが違いを生むのであれば)。

私は<math.h>からisnan()を使用することでこれを解決しました。これは<cmath>には存在しませんでした。最初は#includeingでした。

350
hasen

IEEE規格によると、NaN値には、それに関連する比較が常に常にfalseであるという奇妙な性質があります。つまり、float fの場合、fがNaNの場合、f != fはtrueのみになります。

以下のコメントで指摘したように、コードを最適化するときにすべてのコンパイラがこれを尊重するわけではないことに注意してください。

IEEE浮動小数点を使用すると主張しているコンパイラであれば、このトリックでうまくいくはずです。しかし、実際に機能することを保証するものではありません。疑問がある場合は、コンパイラに確認してください。

333
jalf

現在のC++標準ライブラリには、利用可能なisnan()関数はありません。これは C99 で導入され、関数ではなく マクロ として定義されました。 C99で定義されている標準ライブラリの要素は、現在のC++標準ISO/IEC 14882:1998でも、その更新ISO/IEC 14882:2003でもありません。

2005年に技術報告書1が提案された。 TR1はC99からC++との互換性をもたらします。 C++標準になることが正式に採用されたことはありませんが、多くの( GCC 4.0 + または Visual C++ 9.0 + C++の実装で提供されています。 TR1機能、それらすべて、または一部のみ(Visual C++ 9.0はC99数学関数を提供しません)。

TR1が利用可能な場合、cmathにはisnan()isfinite()などのC99要素が含まれますが、通常はstd::tr1::名前空間で、マクロではなく関数として定義されます。 +)それらを直接std::にインジェクトするので、std::isnanは明確に定義されています。

さらに、C++の実装によっては、C99のC99 isnan()マクロを(cmathまたはmath.hを介して)C++で使用できるようにしているものもありますが、混乱を招く可能性があります。

前述のように、Viusal C++に関するメモはstd::isnanstd::tr1::isnanも提供していませんが、 Visual C++ 6.0 以降で使用可能になった_isnan()として定義された拡張機能を提供します

XCodeでは、もっともっと楽しいものがあります。述べたように、GCC 4+はstd::isnanを定義しています。 XCode形式のコンパイラとライブラリの古いバージョンでは、(ここで 関連性のある議論 です)、Intelでは__inline_isnand()、Powerでは__isnand()の2つの関数が定義されているようです。パソコン.

216
mloskot

最初の解決策:C++ 11を使用している場合

これが求められてから、少し新しい開発がありました:std::isnan()がC++ 11の一部であることを知ることは重要です

あらすじ

ヘッダ<cmath>で定義されています

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

与えられた浮動小数点数argが数値でないかどうかを判定します(NaN)。

パラメータ

arg:浮動小数点値

戻り値

argがtrueの場合はNaN、それ以外の場合はfalse

参照先

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

G ++を使用する場合、これは-fast-mathと互換性がないことに注意してください。他の提案については以下を参照してください。


その他の解決策:C++ 11に準拠していないツールを使用している場合

C99の場合、Cでは、これはint値を返すマクロisnan(c)として実装されています。 xの型は、float、double、またはlong doubleです。

さまざまなベンダが関数isnan()を含んでいてもいなくてもかまいません。

NaNをチェックするためのおそらく移植可能な方法は、NaNがそれ自体と等しくないというIEEE 754プロパティを使用することです。すなわち、xNaNであるためx == xはfalseになります。

ただし、最後のオプションはすべてのコンパイラおよび一部の設定(特に最適化設定)では機能しない可能性があるため、最後の手段として、常にビットパターンを確認できます。

152
BlueTrin

Boostには ヘッダーのみのライブラリ があり、浮動小数点データ型を扱うためのきちんとしたツールがあります。

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

以下の機能があります。

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

BoostのMathツールキット全体に目を通してみると、便利なツールがたくさんあり、急速に成長しています。

また、浮動小数点と非浮動小数点を扱うときは、 数値変換 を見ることをお勧めします。

82
Anonymous

3つの「公式な」方法があります。posixisnanマクロ、c ++ 0xisnan関数テンプレート、またはビジュアルc ++_isnan関数

残念ながら、どちらを使用するのかを検出するのはかなり実用的ではありません。

そして残念ながら、NaNを使ったIEEE 754表現があるかどうかを検出する信頼できる方法はありません。標準ライブラリはそのような公式の方法を提供します(numeric_limits<double>::is_iec559)。しかし、実際にはg ++などのコンパイラはそれを解決します。

理論的には、単純にx != xを使うこともできますが、g ++やビジュアルc ++などのコンパイラではそれが解決されます。

最後に、IEEE 754のような特定の表現を仮定して(そしてある時点で強制的に、強制して)、特定のNaNビットパターンをテストします。


EDIT:「g ++のようなコンパイラ…それを解決する」の例として、考えてみましょう。

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

G ++(TDM-2 mingw32)4.4.1でコンパイルする:

 C:\ test>「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が動作します... || echo!failed 
は動作します... 
 
 C:\ test> gnuc x.cpp --fast-math 
 C:\ test > && echoが動作します... || echo!failed 
アサーションが失敗しました:a!= b、ファイルx.cpp、6行目
 
このアプリケーションは、Runtimeに異常な方法で終了するよう要求しました。詳細については、アプリケーションのサポートチームにお問い合わせください[
]!失敗した[
] [
] C:\ test> _ 
43

コンパイラがc99エクステンションをサポートしている場合はstd :: isnanがありますが、mingwがサポートしているかどうかはわかりません。

これはあなたのコンパイラが標準関数を持っていない場合に動作するはずの小さな関数です:

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

limits標準ライブラリで定義されているnumeric_limits<float>::quiet_NaN( )を使ってテストすることができます。 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;
}

Linux上でg ++でテストしただけなので、これがすべてのプラットフォームで機能するかどうかはわかりません。

25
Bill the Lizard

isnan()関数を使えますが、C数学ライブラリをインクルードする必要があります。

#include <cmath>

この機能はC99の一部なので、どこでも利用できるわけではありません。仕入先が機能を提供していない場合は、互換性のために独自のバリアントを定義することもできます。

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

ナン防止

この質問に対する私の答えは、nanに遡及チェックを使用しないことです。代わりに防止を使用して、形式0.0/0.0の分割をチェックします。

#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は、操作0.f/0.f、または0.0/0.0から生じます。 nanは、コードを安定させるためには、検出しなければならない、および防止されたという非常に慎重なネメシスです。1。通常の数と異なるnanのプロパティ。

  • nanは有毒です。(5 * nan = nan
  • nanは、何も等しくなく、それ自体でもありません(nan!= nan
  • nanは何もしない(nan!> 0)
  • nanは何よりも小さくありません(nan!<0)

リストの最後の2つのプロパティは逆論理であり、nanの数との比較に依存する奇妙なコードの振る舞いになります(最後の3番目のプロパティも奇数ですが、おそらくあなたのコードにx != x ?は表示されないでしょう。 nan(信頼性の低い)をチェックしています)。

私自身のコードでは、nanの値はバグを見つけるのが難しい傾向があることに気づきました。 (これがnotであることに注意してください。infまたは-infの場合(-inf <0)はTRUEを返し、(0 <inf)はTRUEを返し、さらに(-inf <inf) TRUEを返すので、私の経験では、コードの振る舞いはしばしばそれでも望みどおりです。

nanの下で何をするか

0.0/0.0の下で何をしたいのかは特別な場合として処理しなければなりませんが、あなたがすることはあなたがコードから出てくると期待する数に依存しなければなりません。

上の例では、(0.f/FLT_MIN)の結果は基本的に0になります。代わりに0.0/0.0HUGEを生成させることができます。そう、

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.

したがって、上記でxが0.fの場合、infが生成されます(これは実際には上で述べたようにかなり良い/非破壊的な振る舞いをします)。

0による整数除算は実行時例外 を引き起こします。 0.0/0.0が静かにnanと評価されるからといって、怠惰になることができ、それが起こる前に0.0/0.0をチェックしないというわけではありません。

x != xを介したnanのチェックが信頼できない場合があります(特に、x != xスイッチが有効になっている場合、-ffast-mathは、IEEE準拠を破る最適化コンパイラによって取り除かれています)。

12
bobobobo

次のコードはNAN(すべての指数ビットセット、少なくとも1つの小数ビットセット)の定義を使用し、sizeof(int)= sizeof(float)= 4と仮定しています。

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

11
Ian

C++ 14の時点では、浮動小数点数valueがNaNであるかどうかをテストする方法がいくつかあります。

これらの方法のうち、ビットのチェックの数値表現のみが、私の元の回答で述べたように、確実に機能します。特に、std::isnanおよび頻繁に提案されるチェックv != vは、確実に動作せず、使用すべきではありません。誰かが浮動小数点最適化が必要であると判断したときにコードが正しく動作しなくなり、コンパイラーにそれを要求しないようにします。この状況は変化する可能性があり、コンパイラーはより適合性を高めることができますが、この問題については、元の答えから6年間は発生しませんでした。

約6年間、私の最初の答えは、この質問に対する選択された解決策でしたが、それは問題ありませんでした。しかし最近、信頼性の低いv != vテストを推奨する非常に支持の高い回答が選択されました。したがって、この追加の最新の回答(C++ 11およびC++ 14標準、およびC++ 17が公開されています)。


C++ 14の時点でNaN-nessを確認する主な方法は次のとおりです。

  • std::isnan(value) )
    は、C++ 11以降の標準的なライブラリ方法です。 isnanは明らかに同じ名前のPosixマクロと競合しますが、実際にはそれは問題ではありません。主な問題は、浮動小数点演算の最適化が要求されると、少なくとも1つのメインコンパイラ(g ++)でstd::isnanreturns falseがNaN引数になることです。

  • (fpclassify(value) == FP_NAN) )
    std::isnanと同じ問題に苦しんでいます。つまり、信頼できません。

  • (value != value) )
    多くのSO回答で推奨。 std::isnanと同じ問題に苦しんでいます。つまり、信頼できません。

  • (value == Fp_info::quiet_NaN()) )
    これは、標準の動作ではNaNを検出するべきではないが、最適化された動作ではNaNを検出できるテストです(最適化されたコードはビットレベル表現を直接比較するため)。最適化されていない標準の動作では、NaNを確実に検出できます。残念ながら、確実に動作しないことが判明しました。

  • (ilogb(value) == FP_ILOGBNAN) )
    std::isnanと同じ問題に苦しんでいます。つまり、信頼できません。

  • isunordered(1.2345, value) )
    std::isnanと同じ問題に苦しんでいます。つまり、信頼できません。

  • is_ieee754_nan( value ) )
    これは標準機能ではありません。 IEEE 754標準に準拠したビットのチェックです。これは完全に信頼できますが、コードは多少システムに依存します。


次の完全なテストコードの「成功」は、式が値のナンネスを報告するかどうかです。この成功の尺度であるほとんどの式では、NaNとNaNのみを検出するという目標は、標準のセマンティクスに対応しています。ただし、(value == Fp_info::quiet_NaN()) )式の場合、標準の動作は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 ) );
}

G ++の結果((value == Fp_info::quiet_NaN())の標準的な動作は、NaN検出器として機能しないことであることに注意してください)

 [C:\ my\forums\so\282(NaNを検出)] 
> g ++ --version | 「++」を見つける
 g ++(x86_64-win32-sjlj-rev1、Built by MinGW-W64 project)6.3.0 
 
 [C:\ my\forums\so\282(NaNを検出) ] 
> g ++ foo.cpp && a
コンパイラーは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(NaNを検出)] 
> g ++ foo.cpp -ffast-math && a
コンパイラーは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(NaNを検出)] 
> _ 

Visual C++の結果:

 [C:\ my\forums\so\282(NaNを検出)] 
> cl/nologo- 2>&1 | 「++」を見つける
 Microsoft(R)C/C++ Optimizing Compiler Version 19.00.23725 for x86 
 
 [C:\ my\forums\so\282(検出NaN)] 
> cl foo.cpp/Feb && b
 foo.cpp 
コンパイラは、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 (値)== 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成功
 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(NaNを検出)] 
> cl foo.cpp/Feb/fp:fast && b
 foo.cpp 
コンパイラは、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 (値)== 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成功
 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(NaNを検出)] 
> _ 

上記の結果をまとめると、このテストプログラムで定義されたis_ieee754_nan関数を使用したビットレベル表現の直接テストのみが、g ++とVisual C++の両方で確実に機能しました。


補遺:
上記を投稿した後、NaNをテストするためのさらに別の可能性、ここで 別の回答 、つまり((value < 0) == (value >= 0))に言及しました。 Visual C++では問題なく動作することが判明しましたが、g ++の-ffast-mathオプションでは失敗しました。直接ビットパターンテストのみが確実に機能します。

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

sizeof(int)が4でsizeof(long long)が8の場合、これは機能します。

実行時にそれは比較だけです、キャスティングは少し時間がかかりません。同等性をチェックするために比較フラグの設定を変更するだけです。

7
ST3

他の答えを読んだ後、私は浮動小数点比較警告を通り過ぎて、速い数学の下で壊れない何かが欲しかった。次のコードはうまくいくようです。

/*
  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;
}

私にとっては、明示的にインラインにして十分に高速にするための解決策がマクロになる可能性があります。それはどんなfloat型にも働きます。それは、値がそれ自身と等しくない場合のみが値が数値ではない場合であるという事実に基づいています。

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

使用されているNaNの特定のIEEE表現に依存しない可能性のある解決策は、次のようになります。

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

(-ffast-mathオプションを使用する場合のように)(x!= x)がNaNに対して常に保証されているわけではないことを考慮して、私は次のものを使用しています。

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

数は<0と> = 0の両方にすることはできません。そのため、実際には、このチェックは、数がゼロ以下でもゼロ以上でもない場合にのみ合格となります。これは基本的にまったく数ではない、またはNaNです。

あなたが望むならこれを使うこともできます:

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

しかし、これが-ffast-mathの影響をどのように受けているのかわからないので、あなたの走行距離は変わるかもしれません。

4
Jerramy

これは動作します:

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

出力:isnan

3
edW

私にとっては、クロスプラットフォームを使った最善のアプローチは、共用体を使用し、ダブルのビットパターンをテストしてNaNをチェックすることです。

私は徹底的にこの解決策をテストしていません、そしてビットパターンを扱うより効率的な方法があるかもしれません、しかし私はそれがうまくいくべきだと思います。

#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

IEEE規格では、指数がすべて1で仮数がゼロではない場合、数値はNaNになります。 Doubleは1符号ビット、11指数ビット、52仮数ビットです。少しチェックしてください。

0
bop

これは、無限大と、それが二重の制限内にあることを確認することによって、Visual StudioでNaNを検出します。

//#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