web-dev-qa-db-ja.com

ポータブルisnan / isinf関数を作成する方法

Linuxプラットフォームでは、完全に機能するisinfisnan関数を使用しています。しかし、これはOS-Xでは機能しなかったため、LinuxとOS-Xの両方で機能するstd::isinfstd::isnanを使用することにしました。

しかし、Intelコンパイラはそれを認識せず、 http://software.intel.com/en-us/forums/showthread.phpによると、Intelコンパイラのバグだと思います?t = 64188

だから今私は面倒を避け、自分のisinfisnan実装を定義したいだけです。

これがどのように行われるかを誰かが知っていますか?

編集:

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;
}
37
monkeyking

このタスクにboostを使用することもできます。

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

if( boost::math::isnan( ... ) .... )
25
math

私はこれを試していませんが、私は思います

int isnan(double x) { return x != x; }
int isinf(double x) { return !isnan(x) && isnan(x - x); }

うまくいくでしょう。 isinfにはもっと良い方法があるはずですが、うまくいくはずです。

21

this によると、infinityは簡単に確認できます。

  • 符号=正または負の無限大を示す0または1ビット。
  • 指数=すべて1ビット。
  • 仮数=すべて0ビット。

NaNは一意の表現がないため、少し複雑です。

  • 符号= 0または1。
  • 指数=すべて1ビット。
  • 仮数=すべての0ビットを除くすべて(0ビットがすべて無限を表すため)。

以下は、倍精度浮動小数点の場合のコードです。単精度も同様に書くことができます(指数は倍精度の場合は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
16
Amro

これは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.
7
Contango

isnanはC++ 11の一部であり、GCC++に含まれていると思います。Apple LLVM。

現在 MSVC++には_isnan関数<float.h>

適切な #define#includesは適切な回避策を作成する必要があります。

ただし、 nanの検出ではなく、nanが発生しないようにする をお勧めします。

7
bobobobo

まあ、理想的には、インテルがバグを修正するか、回避策を提供するまで待ってください:-)

ただし、IEEE754値からNaNおよびInfを検出する場合は、整数(単精度か倍精度かによって32または64ビット)にマッピングし、指数ビットがすべてかどうかを確認します1.これは、これら2つのケースを示しています。

仮数の上位ビットをチェックすることにより、NaNInfを区別できます。 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コンバーター を浮動小数点分析に非常に役立ちます。

6
paxdiablo

BrubelsabsがBoostがこの機能を提供していると言ったように、報告されたように here を使用する代わりに

if (boost::math::isnan(number))

これを使用する必要があります:

if ((boost::math::isnan)(number))
2
Dexter

誰もが返すC99関数fpclassifyについて言及していないようです:

Argのカテゴリを指定するFP_INFINITE、FP_NAN、FP_NORMAL、FP_SUBNORMAL、FP_ZEROまたは実装定義型のいずれか。

これはビジュアルスタジオで動作しますが、OS-Xについては知りません。

1
rmacheshire

非常にシンプルな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; }
1
Patapom

次の記事には、isnanとisinfに関する興味深いトリックがいくつかあります。 http://jacksondunstan.com/articles/98

0
Rupert