how do I make a portable isnan/isinf function
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;
}
Solution 1:
You could also use boost for this task:
#include <boost/math/special_functions/fpclassify.hpp> // isnan
if( boost::math::isnan( ... ) .... )
Solution 2:
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.
Solution 3:
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
Solution 4:
This works under 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.
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.