VC++中的一個不足及其改善方法 (轉)

gugu99發表於2008-06-16
VC++中的一個不足及其改善方法 (轉)[@more@]

 

VC++中的一個不足及其改善方法

上海七○四研究所
梁柏林

---- 使用C語言序,有時需要把一種數值(如float型別的數值)轉換成另一種型別(如int型別)的數值使用,這時,我們就要用到型別強制轉換運算子,如(int)、(float)等。但是在VC++中,當把一個float型別的數值轉換成int型別時,有時會出現比較大的誤差。我在工作過程中就碰到過,當我把一個值為1140.00的float型變數ftemp使用如下方法轉換成int型別,

itemp=(int)ftemp;


這時,int型變數itemp的值為1139,誤差1(在本文中,我稱這種誤差為“1誤差”)。這麼大的誤差,我們是不能接受的。

---- 經過深入的測試研究,我發現:在VC++中,當一個float型變數初始化(從螢幕輸入一值,或把一常量值賦給它)後就用以上方法轉換成int型別,結果是小數部分去掉,整數部分保留,誤差小於1,沒有“1誤差”;而當一個float型變數初始化後,又經過一些運算,再轉換成int型別,就可能會有“1誤差”,就是說,結果不但把小數部分去掉,整數部分也可能有改變。例如,我們把以米為單位的資料轉化成以釐米為單位的資料,用float型變數f存放以米為單位的資料,用int型變數i存放以釐米為單位的資料,使用下面語句實現資料轉換。

i=(int)(f*100); 當f=11.40(米)時,i=1139(釐米);當f=11.41(米)時,i=1140(釐米);當f=12.32(米)時,i=1231(釐米);當f=12.33(米)時,i=1232(釐米);等等,很多資料的轉換存在著“1誤差”。不過,大部分資料的轉換是沒有誤差的,如當f=11.39(米)時,i=1139(釐米);當f=12.31(米)時,i=1231(釐米)。如果改用以下方法實現資料轉換, “1誤差”一樣存在。 float ftemp; ftemp=f*100; i=(int)ftemp; 這裡,ftemp是一區域性變數(內定義)或全域性變數(函式外定義)。把f*100改成f*100.0, “1誤差”也存在。但是如果把ftemp 改成為類的屬性變數(在類裡定義), “1誤差”就不存在。


---- 我還發現,“1誤差”現象對正負數具有對稱性。就是說,如果有“1誤差”,對於正數,(int)轉換後少了1;對於負數,(int)轉換後多了1。如上例子中,當f=-11.40(米)時,i=-1139(釐米);當f=-11.41(米)時,i=-1140(釐米);當f=-12.32(米)時,i=-1231(釐米);當f=-12.33(米)時,i=-1232(釐米)。而且,轉換誤差不會大於1。

---- 針對以上分析結果,我在這裡給出一個校正“1誤差”的方法,以供參考。我設計了一個把float型數轉換成int型數的函式,用以代替(int)運算子。函式清單如下:

int float_to_int(float f) { int i; float ferror; i=(int)f; ferror=f-(float)i; if(fabs(ferror)>0.99) //有“1誤差”,校正 if(f>0) i++; else i--; return(i); }


---- 在此函式中,透過判斷(int)型別轉換前後的誤差ferror是否大於0.99來判斷是否有“1誤差”,如果有,就進行校正。校正方法是,對於正數,把(int)轉換結果加1;對於負數,把(int)轉換結果減1。

---- 定義了float_to_int()函式後,用它代替(int)運算子就能校正“1誤差”了。如對上面把以米為單位的資料轉化成以釐米為單位的資料這一例子來說,改成

i=float_to_int(f*100); 或 float ftemp; ftemp=f*100; i=float_to_int(ftemp); 當f=11.40(米)時,i=1140(釐米);當f=11.41(米)時,i=1141(釐米);當f=12.32(米)時,i=1232(釐米);當f=12.33(米)時,i=1233(釐米);當f=-11.40(米)時,i=-1140(釐米);當f=-11.41(米)時,i=-1141(釐米);當f=-12.32(米)時,i=-1232(釐米);當f=-12.33(米)時,i=-1233(釐米)。 “1誤差”沒有了。而且對原來沒有 “1誤差”的資料也沒有影響,如當f=11.39 (米)時,i=1139(釐米)。透過對大量的資料進行測試檢查,證明此方法是有效的。


---- 另外,對於double型轉換成int型,也有類似的“1誤差”問題,只是出現誤差的資料比較少,而且還有偶然性(就是,對於某個數值,有時候有“1誤差”,有時候又沒有“1誤差”)。應用類似的方法也可以把double型轉換成int型的“1誤差”校正過來。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1005714/,如需轉載,請註明出處,否則將追究法律責任。

相關文章