浮點數精度計算出現的問題

 

 
 
當咱們保存浮點數後再讀取浮點數,結果可能會出現一點點誤差。
好比:
float ft1 = 20.2;(這樣編譯器會報警告,由於小點數默認爲double)
CString str;
str.Format(_T("%f"),ft1);
這時候ft1的值等於20.200001。
 
float ft2 = 20.8;
CString str;
str.Format(_T("%f"),ft2);
這時候ft1的值等於20.799999。
 
解決方法1:
將float改用double存儲:
double dt1 = 20.2;
 
解決方法2:
使用%g格式化,除去0後的有效位數。
float ft1 = 20.2;
CString str;
str.Format(_T("%g"),ft1);
這時候ft1的值等於20.2。可是無法再用0對齊了,嘿嘿嘿嘿。。。。。。
 
解決方法3:
使用%0.4格式化
float ft1 = 20.2;
CString str;
str.Format(_T("%0.4f"),ft1);
這時候ft1的值等於20.2000。
 
還有些比較複雜的,好比說計算過程當中出現了精度損失。

咱們經過簡單的代碼試驗一下:code

int newWidth, newHeight;

GetThumbnailSize(200, 200, 100, 100, out newWidth, out newHeight);
Console.WriteLine("{0}, {1}", newWidth, newHeight);

GetThumbnailSize(300, 300, 100, 100, out newWidth, out newHeight);
Console.WriteLine("{0}, {1}", newWidth, newHeight);

獲得的結果是:orm

100, 100
99, 100

第一個結果天然沒有問題,可是在第二個結果中爲何是99而不是100?爲此,咱們再經過如下的代碼來觀察一番:ci

ratio: 0.3333333333333333333333333333
new value: 99.99999999999999999999999999
to int: 99

可見,雖然使用了decimal,精度已經很是高的,可是在通過了一除一乘,它仍是沒有恢復到最精確值。雖然一直說要注意浮點數計算時的精度問題,可是對於這個問題許多朋友每每只是理解到「不能直接兩個浮點數相等」,包括我本身的第一印象。但事實上,從上面的結果也能夠看出,把一個浮點數直接轉換成整形,它即是使用了「去尾」而不是「四捨五入」的方法。所以,雖然newValue的值無比接近100,可是在強制去尾後它仍是變成了99。編譯器

若是要在原來的方法中改變這個問題,最簡單的方法多是把最後的強制轉型替換成Math.Round方法。Math.Round方法使用四捨五入,應該可以解決問題。不過若是隻是這樣的話收穫不大,咱們再仔細想一想,應該如何作到儘量的精確。it

兩個浮點數相除可能會喪失精度,但若是是乘法操做,在通常狀況下精度是不會丟失的,除非發生了溢出的話,或者小數位數太多。所以在計算過程當中爲了保持精度,咱們應該儘量的作乘法,而不是做除法。例如如下的判斷:io

if ((decimal)desiredWidth / originalWidth < (decimal)desiredHeight / originalHeight)

其實最好改寫成「等價」的乘法操做。編譯

相關文章
相關標籤/搜索