Linuxプラットフォームでは、完全に機能するisinf
、isnan
関数を使用しています。しかし、これはOS-Xでは機能しなかったため、LinuxとOS-Xの両方で機能するstd::isinf
std::isnan
を使用することにしました。
しかし、Intelコンパイラはそれを認識せず、 http://software.intel.com/en-us/forums/showthread.phpによると、Intelコンパイラのバグだと思います?t = 64188
だから今私は面倒を避け、自分のisinf
、isnan
実装を定義したいだけです。
これがどのように行われるかを誰かが知っていますか?
編集:
isinf
/isnan
を機能させるために、ソースコードでこれを行うことになりました
#include <iostream>
#include <cmath>
#ifdef __INTEL_COMPILER
#include <mathimf.h>
#endif
int isnan_local(double x) {
#ifdef __INTEL_COMPILER
return isnan(x);
#else
return std::isnan(x);
#endif
}
int isinf_local(double x) {
#ifdef __INTEL_COMPILER
return isinf(x);
#else
return std::isinf(x);
#endif
}
int myChk(double a){
std::cerr<<"val is: "<<a <<"\t";
if(isnan_local(a))
std::cerr<<"program says isnan";
if(isinf_local(a))
std::cerr<<"program says isinf";
std::cerr<<"\n";
return 0;
}
int main(){
double a = 0;
myChk(a);
myChk(log(a));
myChk(-log(a));
myChk(0/log(a));
myChk(log(a)/log(a));
return 0;
}
このタスクにboostを使用することもできます。
#include <boost/math/special_functions/fpclassify.hpp> // isnan
if( boost::math::isnan( ... ) .... )
私はこれを試していませんが、私は思います
int isnan(double x) { return x != x; }
int isinf(double x) { return !isnan(x) && isnan(x - x); }
うまくいくでしょう。 isinfにはもっと良い方法があるはずですが、うまくいくはずです。
this によると、infinityは簡単に確認できます。
NaNは一意の表現がないため、少し複雑です。
以下は、倍精度浮動小数点の場合のコードです。単精度も同様に書くことができます(指数は倍精度の場合は11ビット、単精度の場合は8ビットであることを思い出してください)。
int isinf(double x)
{
union { uint64 u; double f; } ieee754;
ieee754.f = x;
return ( (unsigned)(ieee754.u >> 32) & 0x7fffffff ) == 0x7ff00000 &&
( (unsigned)ieee754.u == 0 );
}
int isnan(double x)
{
union { uint64 u; double f; } ieee754;
ieee754.f = x;
return ( (unsigned)(ieee754.u >> 32) & 0x7fffffff ) +
( (unsigned)ieee754.u != 0 ) > 0x7ff00000;
}
実装は非常に簡単です(私は OpenCVヘッダーファイル から取得しました)。これは、同じサイズの符号なし64ビット整数の和集合を使用しており、正しく宣言する必要がある場合があります。
#if defined _MSC_VER
typedef unsigned __int64 uint64;
#else
typedef uint64_t uint64;
#endif
これはVisual Studio 2008で機能します。
#include <math.h>
#define isnan(x) _isnan(x)
#define isinf(x) (!_finite(x))
#define fpu_error(x) (isinf(x) || isnan(x))
安全のため、fpu_error()の使用をお勧めします。 isnan()とisinf()でいくつかの数値が取得されると思いますが、両方を安全にする必要があります。
ここにいくつかのテストコードがあります:
double zero=0;
double infinite=1/zero;
double proper_number=4;
printf("isinf(infinite)=%d.\n",isinf(infinite));
printf("isinf(proper_number)=%d.\n",isinf(proper_number));
printf("isnan(infinite)=%d.\n",isnan(infinite));
printf("isnan(proper_number)=%d.\n",isnan(proper_number));
double num=-4;
double neg_square_root=sqrt(num);
printf("isinf(neg_square_root)=%d.\n",isinf(neg_square_root));
printf("isinf(proper_number)=%d.\n",isinf(proper_number));
printf("isnan(neg_square_root)=%d.\n",isnan(neg_square_root));
printf("isnan(proper_number)=%d.\n",isnan(proper_number));
出力は次のとおりです。
isinf(infinite)=1.
isinf(proper_number)=0.
isnan(infinite)=0.
isnan(proper_number)=0.
isinf(neg_square_root)=1.
isinf(proper_number)=0.
isnan(neg_square_root)=1.
isnan(proper_number)=0.
isnan
はC++ 11の一部であり、GCC++に含まれていると思います。Apple LLVM。
適切な #define
砂 #include
sは適切な回避策を作成する必要があります。
ただし、 nanの検出ではなく、nanが発生しないようにする をお勧めします。
まあ、理想的には、インテルがバグを修正するか、回避策を提供するまで待ってください:-)
ただし、IEEE754値からNaN
およびInf
を検出する場合は、整数(単精度か倍精度かによって32または64ビット)にマッピングし、指数ビットがすべてかどうかを確認します1.これは、これら2つのケースを示しています。
仮数の上位ビットをチェックすることにより、NaN
とInf
を区別できます。 1の場合はNaN
で、それ以外の場合はInf
です。
+/-Inf
は、符号ビットによって指示されます。
単精度(32ビット値)の場合、符号は上位ビット(b31)で、指数は次の8ビット(および23ビットの仮数)です。倍精度の場合、符号は依然として上位ビットですが、指数は11ビット(仮数の場合は52ビット)です。
Wikipedia はすべての悲惨な詳細があります。
次のコードは、エンコーディングの仕組みを示しています。
#include <stdio.h>
static void decode (char *s, double x) {
long y = *(((long*)(&x))+1);
printf("%08x ",y);
if ((y & 0x7ff80000L) == 0x7ff80000L) {
printf ("NaN (%s)\n", s);
return;
}
if ((y & 0xfff10000L) == 0x7ff00000L) {
printf ("+Inf (%s)\n", s);
return;
}
if ((y & 0xfff10000L) == 0xfff00000L) {
printf ("-Inf (%s)\n", s);
return;
}
printf ("%e (%s)\n", x, s);
}
int main (int argc, char *argv[]) {
double dvar;
printf ("sizeof double = %d\n", sizeof(double));
printf ("sizeof long = %d\n", sizeof(long));
dvar = 1.79e308; dvar = dvar * 10000;
decode ("too big", dvar);
dvar = -1.79e308; dvar = dvar * 10000;
decode ("too big and negative", dvar);
dvar = -1.0; dvar = sqrt(dvar);
decode ("imaginary", dvar);
dvar = -1.79e308;
decode ("normal", dvar);
return 0;
}
そしてそれは出力します:
sizeof double = 8
sizeof long = 4
7ff00000 +Inf (too big)
fff00000 -Inf (too big and negative)
fff80000 NaN (imaginary)
ffefdcf1 -1.790000e+308 (normal)
このコード(メソッドではなく)は、過度に移植可能ではないlongのサイズに大きく依存することに注意してください。しかし、情報を取得するために少しいじる必要がある場合は、すでにその領域に入っています:-)
余談ですが、私はいつも Harald SchmidtのIEEE754コンバーター を浮動小数点分析に非常に役立ちます。
BrubelsabsがBoostがこの機能を提供していると言ったように、報告されたように here を使用する代わりに
if (boost::math::isnan(number))
これを使用する必要があります:
if ((boost::math::isnan)(number))
誰もが返すC99関数fpclassifyについて言及していないようです:
Argのカテゴリを指定するFP_INFINITE、FP_NAN、FP_NORMAL、FP_SUBNORMAL、FP_ZEROまたは実装定義型のいずれか。
これはビジュアルスタジオで動作しますが、OS-Xについては知りません。
非常にシンプルなIEEE 754-1985準拠のコードを使用するだけです。
static inline bool ISINFINITE( float a ) { return (((U32&) a) & 0x7FFFFFFFU) == 0x7F800000U; }
static inline bool ISINFINITEPOSITIVE( float a ) { return (((U32&) a) & 0xFFFFFFFFU) == 0x7F800000U; }
static inline bool ISINFINITENEGATIVE( float a ) { return (((U32&) a) & 0xFFFFFFFFU) == 0xFF800000U; }
static inline bool ISNAN( float a ) { return !ISINFINITE( a ) && (((U32&) a) & 0x7F800000U) == 0x7F800000U; }
static inline bool ISVALID( float a ) { return (((U32&) a) & 0x7F800000U) != 0x7F800000U; }
次の記事には、isnanとisinfに関する興味深いトリックがいくつかあります。 http://jacksondunstan.com/articles/98