浮點數計算溢出處理問題、浮點數1.#INF和1.#IND 問題

來源:互聯網
上載者:User

 

昨天遇到了一個關於浮點數計算溢出處理的問題,本來想用 if 語句把條件寫好。

可是遇到了很多困難,上網搜了一下,發現一個解決辦法:

if 語句把條件寫好可以,但是如果遇到冪函數pow(x,y)時,問題就不那麼簡單了。仔細分析將發現:

 

             y
   x  
負小數 負整數 0 整數 小數
負小數 無意義 有意義 有意義 有意義 無意義
負整數 無意義 有意義 有意義 有意義 無意義
0 無意義 無意義 有意義 有意義 有意義
整數 有意義 有意義 有意義 有意義 有意義
小數 有意義 有意義 有意義 有意義 有意義

例如:pow(-1.2,-1.2)=-1.#IND。如果要編程處理,至少需要六個if語句。即使如此,也有麻煩:如何判斷一個double型的變元的值是整數還是小數?

 

為了處理數學函數運算中出現的異常,VC++提供了一個函數_mather,其原型在<math.h>中:

--------------------------------------------------------------------------------------------------------------

所在標頭檔:<math.h>

 

函數原型:int _matherr( struct _exception *except );

函數功能:VC++自動調用此函數來判斷處理數學函數中出現的異常(不能手動調用)

函數傳回值:0傳回值用來標誌一個錯誤,非0值標誌成功。如果返回0,則錯誤資訊可被顯示,錯誤序號被正確設定。如果返回非0值,沒有顯示錯誤資訊,錯誤序號也保持不變。

函數參數:_exception結構包含有如下資料成員:

struct _exception

{
int type 異常類型;
char *name 出錯函數名;
double arg1, arg2 函數的第一和第二(如果有的話)參數;
double retval 函數的傳回值。

}

-------------------------------------------------------------------------------------------------------------

數學函數的錯誤類型定義如下:
_DOMAIN 變元定義域錯誤;
_SING 變元奇異點錯誤;
_OVERFLOW 溢出錯誤;
_PLOSS 精度部分遺失;
_TLOSS 精度丟失;
_UNDERFLOW 下溢錯誤,結果太小,無發表示。

 

 

下面是MSDN給我們提供的一個樣本供大家參考:

/* MATHERR.C illustrates writing an error routine for math  * functions. The error function must be: *      _matherr */#include <math.h>#include <string.h>#include <stdio.h>void main(){    /* Do several math operations that cause errors. The _matherr     * routine handles _DOMAIN errors, but lets the system handle     * other errors normally.     */    printf( "log( -2.0 ) = %e/n", log( -2.0 ) );    printf( "log10( -5.0 ) = %e/n", log10( -5.0 ) );    printf( "log( 0.0 ) = %e/n", log( 0.0 ) );}/* Handle several math errors caused by passing a negative argument * to log or log10 (_DOMAIN errors). When this happens, _matherr * returns the natural or base-10 logarithm of the absolute value * of the argument and suppresses the usual error message. */int _matherr( struct _exception *except ){    /* Handle _DOMAIN errors for log or log10. */    if( except->type == _DOMAIN )    {        if( strcmp( except->name, "log" ) == 0 )        {            except->retval = log( -(except->arg1) );            printf( "Special: using absolute value: %s: _DOMAIN "                     "error/n", except->name );            return 1;        }        else if( strcmp( except->name, "log10" ) == 0 )        {            except->retval = log10( -(except->arg1) );            printf( "Special: using absolute value: %s: _DOMAIN "                     "error/n", except->name );            return 1;        }    }    else    {        printf( "Normal: " );        return 0;    /* Else use the default actions */    }}

輸出結果

Special: using absolute value: log: _DOMAIN error
log( -2.0 ) = 6.931472e-001
Special: using absolute value: log10: _DOMAIN error
log10( -5.0 ) = 6.989700e-001
Normal: log( 0.0 ) = -1.#INF00e+000

 

main函數並沒有調用_matherr函數,為什麼會出現這種情況呢?這就是VC++編譯器為我們做的事情了。它很有可能在數學函數中設定了跳轉來實現異常處理,當數學庫中的符點函數探測到一個錯誤時,就調用此函數。


以上是網上的解決辦法,我自己也想了一下,這樣做的確是比用一般if語句判斷好多了,可是這個是系統自動調用的,在什麼地方調用不知道,什麼時候調用也不知道,不透明,任何的錯誤都在函數中處理,有時候也不方便。

後來經過不斷實驗,我發現,float 和double類型的資料,或是各種數學函數,在發生溢出或錯誤的時候會返回一個異常浮點數,只要我們判斷出這個異常,就可以進一步處理,這樣的處理了方式相對就自由多了。

 

上網找了一些資料:

常見異常的浮點數有:

1.#INF:這個值表示“無窮大inf (infinity 的縮寫)”,即超出了電腦可以表示的浮點數的最大範圍(或者說超過了 double 類型的最大值)。例如,當一個整數除以0時便會得到一個1.#INF / inf值;相應的,如果一個負整數除以0會得到 -1.#INF / -inf 值。

1.#IND:這個的情況更複雜,一般來說,它們來自於任何未定義結果(非法)的浮點數運算。"IND"是 indeterminate 的縮寫,而"nan"是 not a number 的縮寫。產生這個值的常見例子有:對負數開平方,對負數取對數,0.0/0.00.0*∞, ∞/∞ 等。

簡而言之,如果遇到 1.#INF / inf,就檢查是否發生了運算結果溢出除零,而遇到 1.#IND / nan,就檢查是否發生了非法的運算。

 

在vc中,可以用float.h中的,用一下函數來判斷:

int _isnan(double x) 判斷x是不是無效資料(NAN),是返回1,不是返回0

int _finite(double x)判斷x是不是無窮大(1.#INF),是返回0,不是返回非零值

int _fpclass(double x)用於檢驗一個浮點數的類型。

_fpclass的傳回值有:

 _FPCLASS_SNAN     /* signaling NaN */

 _FPCLASS_QNAN     /* quiet NaN */

 _FPCLASS_NINF     /* negative infinity */

 _FPCLASS_NN       /* negative normal */

 _FPCLASS_ND       /* negative denormal */

 _FPCLASS_NZ       /* -0 */

 _FPCLASS_PZ       /* +0 */

 _FPCLASS_PD       /* positive denormal */

 _FPCLASS_PN       /* positive normal */

 _FPCLASS_PINF     /* positive infinity */



到這裡,只要調用函數,VC下浮點數溢出的問題,迎刃而解~~~~~

 

 

 

 

 

http://www.vckbase.com/document/viewdoc/?id=437

http://live.aulddays.com/tech/10/double-float-ind-nan-inf/

http://apple.wish365.net/program-not-a-number/

http://www.cppprog.com/2010/0105/190.html

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.