LoginSignup
8

More than 5 years have passed since last update.

開発環境ごとの NAN isnan

Last updated at Posted at 2016-02-18

開発環境によって 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ファイルを追ってないので、これ以上はわかっていません。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8