如何做便携式isnan/isinf函数?

时间:2022-05-12 12:44:42

I've been using isinf, isnan functions on Linux platforms which worked perfectly. But this didn't work on OS-X, so I decided to use std::isinf std::isnan which works on both Linux and OS-X.

我在Linux平台上使用了isnan函数,它运行得很好。但是这并没有在OS-X上起作用,所以我决定使用std::isnan,它在Linux和OS-X上都有作用。

But the Intel compiler doesn't recognize it, and I guess its a bug in the intel compiler according to http://software.intel.com/en-us/forums/showthread.php?t=64188

但是,英特尔的编译器却不认识它,我猜它是Intel编译器中的一个bug,根据http://software.intel.com/en-us/forums/showthread.php?

So now I just want to avoid the hassle and define my own isinf, isnan implementation.

所以现在我只想避免麻烦和定义我自己的,isnan实现。

Does anyone know how this could be done?

有人知道怎么做吗?

edit:

编辑:

I ended up doing this in my source code for making isinf/isnan working

最后,我在我的源代码中做了这个,以使其能够工作。

#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 个解决方案

#1


25  

You could also use boost for this task:

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

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

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

#2


20  

I've not tried this, but I would think

我没试过,但我想。

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

would work. It feels like there should be a better way for isinf, but that should work.

是可行的。感觉应该有一个更好的方法让伊希夫,但那应该起作用。

#3


13  

According to this, infinity is easy to check:

根据这个,无穷大很容易检查:

  • sign = either 0 or 1 bit indicating positive/negative infinity.
  • 符号= 0或1位表示正/负无穷大。
  • exponent = all 1 bits.
  • 指数=所有1位。
  • mantissa = all 0 bits.
  • mantissa =所有0位。

NaN is a bit more complicated because it doesn't have a unique representation:

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

  • sign = either 0 or 1.
  • 符号= 0或1。
  • exponent = all 1 bits.
  • 指数=所有1位。
  • mantissa = anything except all 0 bits (since all 0 bits represents infinity).
  • mantissa =任何东西,除了所有0位(因为所有0位代表无穷大)。

Below is the code for double-precision floating-point case. Single-precision can be similarly written (recall that the exponent is 11-bits for doubles and 8-bits for singles):

下面是双精度浮点情况的代码。单精度可以写成类似的形式(回想一下,指数是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;
}

The implementation is pretty straightforward (I took those from the OpenCV header files). It uses a union over an equal-sized unsigned 64-bit integer which you might need to correctly declare:

实现非常简单(我从OpenCV头文件中获取了这些文件)。它使用一个与您可能需要正确声明的同等大小的无符号64位整数的联合。

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

#4


7  

This works under Visual Studio 2008:

在Visual Studio 2008中工作:

#include <math.h>
#define isnan(x) _isnan(x)
#define isinf(x) (!_finite(x))
#define fpu_error(x) (isinf(x) || isnan(x))

For safety, I recommend using fpu_error(). I believe some numbers are picked up with isnan(), and some with isinf(), and you need both to be safe.

为了安全起见,我建议使用fpu_error()。我相信一些数字是由isnan()和一些使用了isinf()获得的,您需要两者都是安全的。

Here is some test code:

下面是一些测试代码:

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));

Here is the output:

这是输出:

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.

#5


7  

isnan is part of C++11 now, included in GCC++ I believe, and Apple LLVM.

isnan现在是c++ 11的一部分,我相信它包含在GCC++中,还有Apple LLVM。

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

现在msvc++在 中有一个_isnan函数。

Appropriate #defines and #includes should make a suitable workaround.

适当的#定义和#include应该使一个合适的解决方案。

However, I recommend preventing nan from ever occurring, instead of nan detection.

但是,我建议不要让nan出现,而不是nan检测。

#6


6  

Well, ideally, you'd wait until Intel fixes the bug or provides a workaround :-)

理想情况下,你应该等到英特尔修复bug或提供解决方案:-)

But if you want to detect NaN and Inf from IEEE754 values, map it to an integer (32 or 64 bit depending on whether it's single or double precision) and check if the exponent bits are all 1. This indicates those two cases.

但是,如果您想从IEEE754值中检测NaN和Inf,将它映射到一个整数(32或64位,取决于它是单精度还是双精度),并检查指数位是否都为1。这说明了这两种情况。

You can distinguish between NaN and Inf by checking the high order bit of the mantissa. If it's 1, that's NaN otherwise Inf.

您可以通过检查mantissa的高阶位来区分NaN和Inf。如果是1,那是NaN,否则是Inf。

+/-Inf is dictated by the sign bit.

+/-Inf由符号位决定。

For single precision (32-bit values), the sign is the high-order bit (b31), exponent is the next eight bits (plus a 23-bit mantissa). For double precision, the sign is still the high-order bit but the exponent is eleven bits (plus 52 bits for the mantissa).

对于单精度(32位值),符号是高阶位(b31),指数是下一个8位(加上一个23位的尾数)。对于双精度,符号仍然是高阶位,但指数为11位(加上尾数的52位)。

Wikipedia has all the gory details.

*拥有所有血淋淋的细节。

The following code shows you how the encoding works.

下面的代码向您展示了编码是如何工作的。

#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;
}

and it outputs:

输出:

sizeof double = 8
sizeof long   = 4
7ff00000 +Inf (too big)
fff00000 -Inf (too big and negative)
fff80000 NaN  (imaginary)
ffefdcf1 -1.790000e+308 (normal)

Just keep in mind that this code (but not the method) depends a great deal on the sizes of your longs which is not overly portable. But, if you have to bit-fiddle to get the information, you've already entered that territory :-)

请记住,这段代码(但不是方法)很大程度上取决于您的longs的大小,因为它不太便于移植。但是,如果你想要获取信息,你已经进入了这个领域:-)

As an aside, I've always found Harald Schmidt's IEEE754 converter very useful for floating point analysis.

顺便说一句,我一直认为Harald Schmidt的IEEE754转换器对于浮点分析非常有用。

#7


2  

As brubelsabs said Boost offers this feature but, as reported here, instead of using

正如brubelsabs所说,Boost提供了这一特性,但正如这里所报道的,它没有使用。

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

This should be used:

这应该使用:

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

#8


1  

No-one seems to have mentioned the C99 function fpclassify which returns:

似乎没有人提到C99函数fpcategory,它返回:

One of FP_INFINITE, FP_NAN, FP_NORMAL, FP_SUBNORMAL, FP_ZERO or implementation-defined type, specifying the category of arg.

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

This works with visual studio, but I don't know about OS-X.

这与visual studio有关,但我不知道OS-X。

#9


0  

The following article has some interesting tricks for isnan and isinf: http://jacksondunstan.com/articles/983

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

#10


0  

Just use that super simple IEEE 754-1985-compliant code:

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

#11


-2  

this works on osx

这是在osx

#include <math.h>

also this might be portable,

这可能是便携式的,

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

edit:

编辑:

as Chris pointed out the above may fail with large x

正如克里斯指出的,上面的可能会失败。

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

#1


25  

You could also use boost for this task:

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

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

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

#2


20  

I've not tried this, but I would think

我没试过,但我想。

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

would work. It feels like there should be a better way for isinf, but that should work.

是可行的。感觉应该有一个更好的方法让伊希夫,但那应该起作用。

#3


13  

According to this, infinity is easy to check:

根据这个,无穷大很容易检查:

  • sign = either 0 or 1 bit indicating positive/negative infinity.
  • 符号= 0或1位表示正/负无穷大。
  • exponent = all 1 bits.
  • 指数=所有1位。
  • mantissa = all 0 bits.
  • mantissa =所有0位。

NaN is a bit more complicated because it doesn't have a unique representation:

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

  • sign = either 0 or 1.
  • 符号= 0或1。
  • exponent = all 1 bits.
  • 指数=所有1位。
  • mantissa = anything except all 0 bits (since all 0 bits represents infinity).
  • mantissa =任何东西,除了所有0位(因为所有0位代表无穷大)。

Below is the code for double-precision floating-point case. Single-precision can be similarly written (recall that the exponent is 11-bits for doubles and 8-bits for singles):

下面是双精度浮点情况的代码。单精度可以写成类似的形式(回想一下,指数是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;
}

The implementation is pretty straightforward (I took those from the OpenCV header files). It uses a union over an equal-sized unsigned 64-bit integer which you might need to correctly declare:

实现非常简单(我从OpenCV头文件中获取了这些文件)。它使用一个与您可能需要正确声明的同等大小的无符号64位整数的联合。

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

#4


7  

This works under Visual Studio 2008:

在Visual Studio 2008中工作:

#include <math.h>
#define isnan(x) _isnan(x)
#define isinf(x) (!_finite(x))
#define fpu_error(x) (isinf(x) || isnan(x))

For safety, I recommend using fpu_error(). I believe some numbers are picked up with isnan(), and some with isinf(), and you need both to be safe.

为了安全起见,我建议使用fpu_error()。我相信一些数字是由isnan()和一些使用了isinf()获得的,您需要两者都是安全的。

Here is some test code:

下面是一些测试代码:

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));

Here is the output:

这是输出:

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.

#5


7  

isnan is part of C++11 now, included in GCC++ I believe, and Apple LLVM.

isnan现在是c++ 11的一部分,我相信它包含在GCC++中,还有Apple LLVM。

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

现在msvc++在 中有一个_isnan函数。

Appropriate #defines and #includes should make a suitable workaround.

适当的#定义和#include应该使一个合适的解决方案。

However, I recommend preventing nan from ever occurring, instead of nan detection.

但是,我建议不要让nan出现,而不是nan检测。

#6


6  

Well, ideally, you'd wait until Intel fixes the bug or provides a workaround :-)

理想情况下,你应该等到英特尔修复bug或提供解决方案:-)

But if you want to detect NaN and Inf from IEEE754 values, map it to an integer (32 or 64 bit depending on whether it's single or double precision) and check if the exponent bits are all 1. This indicates those two cases.

但是,如果您想从IEEE754值中检测NaN和Inf,将它映射到一个整数(32或64位,取决于它是单精度还是双精度),并检查指数位是否都为1。这说明了这两种情况。

You can distinguish between NaN and Inf by checking the high order bit of the mantissa. If it's 1, that's NaN otherwise Inf.

您可以通过检查mantissa的高阶位来区分NaN和Inf。如果是1,那是NaN,否则是Inf。

+/-Inf is dictated by the sign bit.

+/-Inf由符号位决定。

For single precision (32-bit values), the sign is the high-order bit (b31), exponent is the next eight bits (plus a 23-bit mantissa). For double precision, the sign is still the high-order bit but the exponent is eleven bits (plus 52 bits for the mantissa).

对于单精度(32位值),符号是高阶位(b31),指数是下一个8位(加上一个23位的尾数)。对于双精度,符号仍然是高阶位,但指数为11位(加上尾数的52位)。

Wikipedia has all the gory details.

*拥有所有血淋淋的细节。

The following code shows you how the encoding works.

下面的代码向您展示了编码是如何工作的。

#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;
}

and it outputs:

输出:

sizeof double = 8
sizeof long   = 4
7ff00000 +Inf (too big)
fff00000 -Inf (too big and negative)
fff80000 NaN  (imaginary)
ffefdcf1 -1.790000e+308 (normal)

Just keep in mind that this code (but not the method) depends a great deal on the sizes of your longs which is not overly portable. But, if you have to bit-fiddle to get the information, you've already entered that territory :-)

请记住,这段代码(但不是方法)很大程度上取决于您的longs的大小,因为它不太便于移植。但是,如果你想要获取信息,你已经进入了这个领域:-)

As an aside, I've always found Harald Schmidt's IEEE754 converter very useful for floating point analysis.

顺便说一句,我一直认为Harald Schmidt的IEEE754转换器对于浮点分析非常有用。

#7


2  

As brubelsabs said Boost offers this feature but, as reported here, instead of using

正如brubelsabs所说,Boost提供了这一特性,但正如这里所报道的,它没有使用。

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

This should be used:

这应该使用:

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

#8


1  

No-one seems to have mentioned the C99 function fpclassify which returns:

似乎没有人提到C99函数fpcategory,它返回:

One of FP_INFINITE, FP_NAN, FP_NORMAL, FP_SUBNORMAL, FP_ZERO or implementation-defined type, specifying the category of arg.

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

This works with visual studio, but I don't know about OS-X.

这与visual studio有关,但我不知道OS-X。

#9


0  

The following article has some interesting tricks for isnan and isinf: http://jacksondunstan.com/articles/983

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

#10


0  

Just use that super simple IEEE 754-1985-compliant code:

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

#11


-2  

this works on osx

这是在osx

#include <math.h>

also this might be portable,

这可能是便携式的,

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

edit:

编辑:

as Chris pointed out the above may fail with large x

正如克里斯指出的,上面的可能会失败。

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