開発環境によって NAN と isnan の実装が異なることがあります。
この違いをまとめた記事は見つけられなかったので、調べた結果を残します。
調査環境
OS
Win7(x64)
g++ (mingw)
version 4.4.0
VC(VS2010)
Microsoft Visual C++ 2010 01018-532-2002102-70331
NAN
非数リテラル。マクロで定義されていたり、定義されていなかったりします。
g++ (mingw)
NAN が mingw/include/math.h 定義されています。
// #include <math.h>
// または
// #include <cmath>
double g = NAN; // g is NAN
VC(VS2010)
Microsoft Visual C++ 2010 01018-532-2002102-70331
NAN は定義されていません。
公式リファレンスでは、以下の実装が記載されています。
unsigned long nan[2]={0xffffffff, 0x7fffffff};
double g = *( double* )nan; // g is NAN
( https://msdn.microsoft.com/ja-jp/library/w22adx1s.aspx より引用)
NANを定義する
g++ライクに定義する場合、これをマクロで定義する方法があります。
#ifndef NAN
static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
#define NAN (*(const float *) __nan)
#endif
( http://mjhd.hatenablog.com/entry/how-to-define-nan-in-vc より引用)
定義の方法はいくつかあります。
マクロで定義する場合、次のような定義もできます。
#ifndef NAN
#include <limits> // numeric_limits<T>::quiet_NaN()
#define NAN std::numeric_limits<double>::quiet_NaN()
#endif
( http://www.cplusplus.com/reference/limits/numeric_limits/ )
このほか、マクロを利用せずグローバルなstatic定数や無名空間定数にする方法もあります。
#ifndef NAN
#include <limits> // numeric_limits<T>::quiet_NaN()
const static NAN (std::numeric_limits<double>::quiet_NaN())
#endif
#ifndef NAN
#include <limits> // numeric_limits<T>::quiet_NaN()
namespace
{
const double NAN ( std::numeric_limits<double>::quiet_NaN() );
}
#endif
isnan
引数が NaN であるかを判定する関数です。
NaNはその性質から比較演算子では比較できない言語が多く、C++においてもisnanを用いて判定します。
マクロやテンプレート関数で定義されています。
g++ (mingw)
isnan が mingw\include\math.h 定義されています。
// #include <math.h>
bool result;
result = isnan(NAN); // result = true (=(bool)1)
result = _isnan(NAN); // _isnan も定義されている(float.hより)
result = __isnan(NAN); // __isnan も定義されている
※ただし、この isnan はマクロである。実際には__isnan が呼ばれている。
include を cmath に変更すると isnan マクロは使えなくなります。
これはincludeファイルが以下に変わるためです。
mingw\lib\gcc\mingw32\4.4.0\include\c++\cmath
その代わりにテンプレートを使用した isnan が利用できます。
ただし、std名前空間に存在しているので注意が必要です。
// #include <cmath>
bool result;
//result = isnan(NAN); // error
result = std::isnan(NAN); // ok
result = _isnan(NAN); // _isnan __isnan も同様に使える
result = __isnan(NAN);
_isnan __isnan が使えるのは、cmath が math.h を include しているからです。
isnan が使えないのは undef で無効化しているためです。
( http://sealsoft.jp/namespace.html )
( http://sealsoft.jp/namespace.html )
VC(VS2010)
float.hに _isnan のみ定義されています。
// #include <float.h>
bool result;
unsigned long nan[2]={0xffffffff, 0x7fffffff};
double g = *( double* )nan; // g is NAN
result = _isnan(g); // result is true (=(bool)1)
VS は簡単にしかincludeファイルを追ってないので、これ以上はわかっていません。