2010-02-12 37 views
36

我一直在使用isinf,isnan函數在Linux平臺上工作完美。 但是這在OS-X上不起作用,所以我決定使用std::isinfstd::isnan,它可以在Linux和OS-X上運行。我該如何製作一個便攜式isnan/isinf函數

但英特爾編譯器無法識別它,我根據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; 
} 
+1

密切相關:[如果使用雙__Checking(或浮動)爲NaN在C++ __](HTTP://計算器。 com/questions/570669/checking-if-a-double-or-float-is-nan-in-c) – bobobobo

回答

20

我還沒有試過,但我認爲

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

會工作。感覺就像isinf應該有更好的方法,但這應該起作用。

+0

我已經做了類似於你的isnan函數的東西,它可以在Windows,Linux和OS X上工作。 –

+0

This不適用於intel編譯器 – monkeyking

+15

這個(x!= x)不能在MSVC或gcc中使用快速數學標誌(即如果浮點實現不符合IEEE)。請參閱http://msdn.microsoft.com/en-us/library/e7s85ffb.aspx –

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對於浮點分析非常有用。

+2

不幸的是,表達式'*(((long *)(&x))+ 1)'調用了未定義的行爲:在指向'long *'的指針強制轉換之後,允許編譯器推斷生成的指針不是別名與原來的一樣,因爲一個指向一個「長」而另一個指向一個「雙」,並對其進行優化。當編譯器決定內聯decode()時,這可能會成爲一個問題,因爲它會允許編譯器移動讀取浮點數前面的整數,這顯然會產生垃圾。爲了安全起見,使用'memcpy()'而不是強制轉換。 – cmaster

-1

這個工程在OSX

#include <math.h> 

也這可能是便攜式,

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

編輯:

克里斯指出,上述可能無法與大型X

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

有時候這不能給你錯誤的答案嗎?如果x足夠大,它不會以整數精度記錄數字。 (即1.2345 * 2^100-1 = 1.2345 * 2^100,但是1.2345 * 2^100!=無窮大) – Chris

+2

糟糕,int isinf(double x){return x == x * 2; }版本,您現在有isinf(0.0)... –

+0

如果x * 2溢出? –

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

_finite對inf *和* nan都返回false,所以你的isinf實現是不正確的 - 事實上,你自己的演示輸出顯示:-) –

+0

很高興知道 - 謝謝! – Contango

25

您也可以使用升壓此任務:

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

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

是的,帶上約7000個頭文件來解決一個可以用2或3行解決的問題。 – Eric

+31

你不必使用它,但如果有人仍然使用boost,無論如何,這是一個相當便攜和短的解決方案。沒有#IFDEFs,赫赫? – math

+1

OP的問題是「我如何創建一個便攜式isnan/isinf函數」。 OP很清楚自己想要實現它。這個答案應該發佈爲評論,而不是答案。它不回答這個問題,更糟的是它建議使用一個巨大的庫。 – plasmacel

2

正如brubelsabs所述升報價此功能但是,如報告here,而不是使用

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

這應該被用於:

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

根據this無窮很容易檢查:

  • 標誌= 0或1比特指示正/負無窮大。
  • exponent =全1位。
  • 尾數=全0位。

的NaN是更復雜一些,因爲它不具有唯一表示:

  • 標誌= 0或1。
  • exponent =全1位。
  • 尾數=除了全部0位以外的任何東西(因爲所有的0位都代表無窮大)。

下面是雙精度浮點格的代碼。單精度可以類似地寫成(記得指數是雙打和8位單打11位):

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 
+1

如果有人對此感興趣,那OpenCV中的定義就轉移了,現在它在'hal'模塊中。這是一個更加永久的鏈接:https://github.com/Itseez/opencv/blob/3.0.0/modules/hal/include/opencv2/hal/defs.h#L447 – Amro

+2

+1這顯然是最平臺的獨立的方法可以保證在不需要包含庫和不考慮編譯器設置的情況下得到正確的答案。 –

1

沒有人似乎已經提到的C99功能fpclassify返回:

一個FP_INFINITE的,FP_NAN,FP_NORMAL,FP_SUBNORMAL,FP_ZERO或實現定義的類型,指定arg的類別。

這適用於visual studio,但我不知道OS-X。

0

只需使用超級簡單符合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; }