Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do I make a portable isnan/isinf function

Tags:

c++

c

function

math

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.

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

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

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;
}
like image 492
monkeyking Avatar asked Feb 12 '10 01:02

monkeyking


3 Answers

You could also use boost for this task:

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

if( boost::math::isnan( ... ) .... )
like image 160
math Avatar answered Nov 09 '22 16:11

math


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.

like image 23
Johann Hibschman Avatar answered Nov 09 '22 17:11

Johann Hibschman


According to this, infinity is easy to check:

  • sign = either 0 or 1 bit indicating positive/negative infinity.
  • exponent = all 1 bits.
  • mantissa = all 0 bits.

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

  • sign = either 0 or 1.
  • exponent = all 1 bits.
  • mantissa = anything except all 0 bits (since all 0 bits represents infinity).

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

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:

#if defined _MSC_VER
  typedef unsigned __int64 uint64;
#else
  typedef uint64_t uint64;
#endif
like image 18
Amro Avatar answered Nov 09 '22 16:11

Amro