如何制作便携式isnan / isinf功能

时间:2010-02-12 01:40:30

标签: c++ c math function

我一直在Linux平台上使用isinfisnan函数,这些函数运行良好。 但是这对OS-X不起作用,所以我决定使用适用于Linux和OS-X的std::isinf std::isnan

但英特尔编译器无法识别它,我猜它是英特尔编译器中的一个错误,根据http://software.intel.com/en-us/forums/showthread.php?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;
}

11 个答案:

答案 0 :(得分:25)

你也可以使用boost来完成这项任务:

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

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

答案 1 :(得分:20)

我没试过这个,但我想是

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

会奏效。感觉isinf应该有更好的方法,但这应该有用。

答案 2 :(得分:15)

根据this无穷大很容易检查:

  • sign = 0或1位表示正/负无穷大。
  • 指数=全1位。
  • 尾数=全0位。

NaN 有点复杂,因为它没有唯一的表示形式:

  • sign = 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 header files中获取了这些内容)。它使用一个与大小相等的无符号64位整数的并集,您可能需要正确声明:

#if defined _MSC_VER
  typedef unsigned __int64 uint64;
#else
  typedef uint64_t uint64;
#endif

答案 3 :(得分:7)

这适用于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.

答案 4 :(得分:7)

isnan现在是C ++ 11的一部分,包括在我认为的GCC ++和Apple LLVM中。

现在MSVC++ has an _isnan function in <float.h>.

适当的#define#include应该做出合适的解决方法。

但是,我建议preventing nan from ever occurring, instead of nan detection

答案 5 :(得分:6)

嗯,理想情况下,您要等到英特尔修复错误或提供解决方法: - )

但是如果要从IEEE754值中检测NaNInf,请将其映射为整数(32或64位,具体取决于它是单精度还是双精度)并检查指数位是否为全部1.这表明了这两种情况。

您可以通过检查尾数的高位来区分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)

请记住,这段代码(但不是方法)在很大程度上取决于你的长片的大小,而这些大小并不过分便携。但是,如果你不得不小心翼翼地获取信息,那么你已经进入了这个领域: - )

顺便说一句,我总是发现Harald Schmidt's IEEE754 converter对浮点分析非常有用。

答案 6 :(得分:2)

正如brubelsabs所说,Boost提供此功能,但正如报道here,而不是使用

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

应该使用:

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

答案 7 :(得分:1)

似乎没有人提到过返回的C99函数fpclassify:

FP_INFINITE,FP_NAN,FP_NORMAL,FP_SUBNORMAL,FP_ZERO或实现定义类型之一,指定arg的类别。

这适用于visual studio,但我不了解OS-X。

答案 8 :(得分:1)

只需使用超级简单的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; }

答案 9 :(得分:0)

以下文章为isnan和isinf提供了一些有趣的技巧: http://jacksondunstan.com/articles/983

答案 10 :(得分:-2)

这适用于osx

#include <math.h>

这也可以是便携式的,

int isinf( double x ) { return x == x - 1; }

编辑:

正如克里斯指出的那样,上面可能会因大x而失败

int isinf( double x ) { return x == x * 2; }