2010-06-23 94 views
2

我有一個處理一些地理座標在.NET中的方法,我有一個結構,存儲一個座標對,如果256傳入一個座標,它變爲0.但是,在一個特定的實例計算大約255.99999998的值,並因此存儲在結構中。當它在ToString()中打印時,它變成了256,這不應該發生 - 256應該是0.我不介意打印255.9999998,但是當調試器顯示255.99999998時打印256是一個問題。它存儲和顯示0會更好。如何解決一些舍入錯誤?

特別是有比較的問題。 255.99999998足夠接近256,所以它應該等於它。比較雙打時我應該怎麼做?使用某種類型的epsilon值?


編輯:具體來說,我的問題是,我需要一個值,執行一些計算,然後對這個數字進行計算相反,我需要找回原來的值準確。

+0

使用epsilon是比較浮點值的唯一合法方法。 abs(a - b)<= eps – Andrey 2010-06-23 01:37:38

+0

將兩個浮點數與==進行比較是完全合法的,因此幾乎沒有任何編譯器抱怨它。然而,最小的四捨五入誤差會導致這兩個值在數學說他們應該是不相等的,這就是爲什麼如果你重視你的理智不建議。 – cHao 2010-06-23 02:08:52

+0

如果您確實只需要將原始值準確恢復,您是不是可以直接存儲它,或者是關於原始計算過程的一些信息以及數字? – 2010-06-24 18:52:13

回答

1

您可以使用epsilon方法,但是epsilon通常是解決浮點算法有損的事實的一種巧妙方法。

你可能會考慮完全避免二進制浮點,並使用一個很好的Rational類。

如果您使用Rational類型進行無損算術運算,上面的計算可能註定是256。

理性類型可以通過比率或成分類的名稱去了,是相當簡單寫

這裏有一個example。 這裏的another


編輯....

要了解你的問題考慮,當十進制值0.01轉換爲二進制表示它不能準確地存儲在內存有限。該值的十六進制表示是0.028F5C28F5C,其中「28F5C」無限重複。所以即使在進行任何計算之前,只要將二進制格式存儲爲0.01就可以避免精確性。

理性和小數類用於克服這個問題,雖然性能成本。通過存儲分子和分母來表示您的價值,Rational類型可避免此問題。十進制類型使用二進制編碼的十進制format,這可能是劃分中的有損分量,但可以精確地存儲常見的十進制值。

爲了您的目的,我仍然建議使用Rational類型。

3

這聽起來像打印號碼的問題,而不是如何存儲。 A double約有15位有效數字,因此它可以從256中精確地分辨出255.99999998。

1

您可以選擇格式字符串,讓您根據需要顯示儘可能多的數字。

通常比較雙等於相等的方法是將它們相減,看看絕對值是否小於某個預定義的epsilon,可能是0.000001。

+0

使用R格式說明符而不是默認的G使它顯示正確的值。 – 2010-06-23 03:09:00

0

您必須在兩個值相等的閾值上自行決定。這相當於使用所謂的定點數(而不是浮點)。然後,您必須手動執行取整。

我會用一些未簽名的類型與已知的大小(例如,UINT32 UINT64或者,如果他們提供,我不知道.NET)去把它作爲一個固定點數量型模256

例如。

typedef uint32 fixed; 

inline fixed to_fixed(double d) 
{ 
    return (fixed)(fmod(d, 256.) * (double)(1 << 24)) 
} 

inline double to_double(fixed f) 
{ 
    return (double)f/(double)(1 << 24); 
} 

或更多的東西,以適應舍入約定(到最近,從低到高,從奇數到偶數)。固定的最高8位保存整數部分,低24位保存小數部分。絕對精度爲2^{ - 24}。

請注意,添加和減去這些數字自然會在256處包裝。對於乘法,您應該小心。