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

mon*_*ing 37 c c++ math function

我一直在使用isinf,isnan在Linux平台上运行完美的功能.但是这在OS-X上不起作用,所以我决定使用std::isinf std::isnan哪种适用于Linux和OS-X.

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

mat*_*ath 25

您还可以使用boost来执行此任务:

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

if( boost::math::isnan( ... ) .... )
Run Code Online (Sandbox Code Playgroud)

  • 是的,带来~7000个头文件来解决可以用2或3行解决的问题. (45认同)
  • 你不必使用它,但如果有人仍然使用boost,这是一个非常便携和简短的解决方案.没有#IFDEFs,嘿? (34认同)
  • 幸运的是Boost是开源的,所以他也可以阅读实现来猜测如何解决这个问题.由于OP提到他在预定义的isnan isinf函数之前使用过,他可能不需要重新发明轮子.如果这里的lib的大小确实是一个问题,那么你是ASSUMING!,比这里发布的其他解决方案或Boost可能会有所帮助.除非他没有规定尺寸,否则不要优先考虑是安全的!BTW他提到的错误同时被修复了. (4认同)
  • OP的问题是"我如何制作便携式isnan/isinf功能".很明显OP希望自己实现它.这个答案应该作为评论发布,而不是答案.它没有回答这个问题,更糟糕的是它建议使用一个巨大的库. (2认同)

Joh*_*man 21

我没试过,但我想

int isnan(double x) { return x != x; }
int isinf(double x) { return !isnan(x) && isnan(x - x); }
Run Code Online (Sandbox Code Playgroud)

会工作.感觉isinf应该有更好的方法,但这应该有效.

  • 这个(x!= x)在带有快速数学标志的MSVC或gcc中不起作用(即浮点实现不符合IEEE).请参阅http://msdn.microsoft.com/en-us/library/e7s85ffb.aspx (16认同)
  • 还有`int isinf(double x){return fabs(x)> DBL_MAX; }`. (2认同)
  • @monkeyking:它怎么行不通? (2认同)

Amr*_*mro 16

根据,无穷远很容易检查:

  • 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;
}
Run Code Online (Sandbox Code Playgroud)

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

#if defined _MSC_VER
  typedef unsigned __int64 uint64;
#else
  typedef uint64_t uint64;
#endif
Run Code Online (Sandbox Code Playgroud)

  • 如果有人感兴趣,OpenCV中的那个定义就会移动,现在它在`hal`模块中.这是一个更永久的链接:https://github.com/Itseez/opencv/blob/3.0.0/modules/hal/include/opencv2/hal/defs.h#L447 (2认同)
  • +1这显然是最平台无关的方法,可以保证获得正确答案,而无需包含库,也不需要考虑编译器设置. (2认同)

Con*_*ngo 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))
Run Code Online (Sandbox Code Playgroud)

为安全起见,我建议使用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));
Run Code Online (Sandbox Code Playgroud)

这是输出:

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.
Run Code Online (Sandbox Code Playgroud)

  • _finite对于inf*和*nan都返回false,所以你的isinf实现是不正确的 - 实际上,你自己的demo输出显示:-) (4认同)

bob*_*obo 7

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

现在MSVC++有一个_isnan功能<float.h>.

适当的#defines和#includes应该做出合适的解决方法.

但是,我建议防止纳米发生,而不是纳米检测.

  • 有时,您无法控制数据中是否存在 nan,特别是如果数据不是您发起的,并且输出仍然需要了解这些 nan。 (2认同)

pax*_*blo 6

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

但是,如果要检测NaN,并Inf从IEEE754值,其映射到一个整数(32位或64位取决于它是否是单或双精度),并检查指数位都是1.这表明这两个案件.

您可以通过检查尾数的高位来区分NaNInf.如果是1,那就NaN不是了Inf.

+/-Inf 由符号位决定.

对于单精度(32位值),符号是高位(b31),指数是接下来的8位(加上23位尾数).对于双精度,符号仍然是高位,但指数是11位(尾数加52位).

维基百科拥有所有血腥的细节.

以下代码显示了编码的工作原理.

#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;
}
Run Code Online (Sandbox Code Playgroud)

它输出:

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

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

顺便说一句,我总是发现Harald Schmidt的IEEE754转换器对浮点分析非常有用.

  • 不幸的是,表达式`*(((long*)(&x))+ 1)`调用未定义的行为:在指向`long*`的转换之后,允许编译器推断出结果指针没有别名原始的,因为一个指向"long"而另一个指向"double",并对其执行优化.当编译器决定内联`decode()`时,这可能会成为一个问题,因为它允许编译器在浮点写入之前移动读取的整数,这显然会产生垃圾.为了安全起见,请使用`memcpy()`而不是强制转换. (2认同)

归档时间:

查看次数:

38522 次

最近记录:

9 年,2 月 前