比較小數的最佳方法是什麼?比較小數的最佳方法是什麼?
可以說我有2個值,比如3.45
和3.44
,可靠地比較它們的最好方法是什麼?
我正在考慮將所有數字都存儲爲345
和344
,以便我只比較整個數字,並且僅向用戶顯示帶有小數點的格式化數字。
另一種解決方案是使用自定義函數來測試差異,當差值小於0.01
時,數字應該相等。
什麼是其他可能的解決方案(更好的解決方案)?
比較小數的最佳方法是什麼?比較小數的最佳方法是什麼?
可以說我有2個值,比如3.45
和3.44
,可靠地比較它們的最好方法是什麼?
我正在考慮將所有數字都存儲爲345
和344
,以便我只比較整個數字,並且僅向用戶顯示帶有小數點的格式化數字。
另一種解決方案是使用自定義函數來測試差異,當差值小於0.01
時,數字應該相等。
什麼是其他可能的解決方案(更好的解決方案)?
最常見的技術是使用epsilon(您所描述的第二件事)。儘管如此,製作一個適用於所有輸入數字的通用epsilon可能非常困難/不可能。如果你處理0.00001左右的數字或10億左右的數字,0.01的ε值對你來說可能會很糟糕。閱讀this以獲得對epsilon技術的全面分析。
您所描述的第一種解決方案在時間數學中很常見。一切都以整數個滴答表示。滴答可以代表1秒,或1毫秒,或任何你想要的。如果你喜歡,你可以將它們轉換成另一個單位的小數,或者比較它們。唯一的問題是你確實需要選擇一個刻度大小,沒有任何東西可以表示小於1的刻度單位。
這也被稱爲「模糊比較」,允許這兩個值有點不同(公差,也稱爲「epsilon」)。通常,這樣一個ε值大約在1E-6
到1E-10
之間,但是您發現應用程序中較小或較大的值更適合:在您的示例中,epsilon不應小於1E-2 = 0.01
。一旦你找到了一個適合你需要的epsilon值,你可以編寫如下的比較函數集(寫在C和C++的通用子集中;它們應該適用於幾乎所有的面向對象/過程語言輕微的變化):
const double fuzzyEpsilon = 1E-6; // just an example!
bool fuzzyEqual(double a, double b) {
return (abs(a - b) <= fuzzyEpsilon);
}
bool fuzzyUnqual(double a, double b) {
return (abs(a - b) > fuzzyEpsilon);
}
int fuzzyCompare(double a, double b) {
return ((a - b) > fuzzyEpsilon) - ((b - a) > fuzzyEpsilon);
}
第三函數返回的-1
一個代碼,0
,1
如果a < b
,a == b
,a > b
分別與模糊比較(類似於strcmp
)。該實現假定編程語言將布爾值隱式轉換爲0
(false)和1
(true)。如果不是,請使用以下內容:
int fuzzyCompare(double a, double b) {
return (a - b) > fuzzyEpsilon ? 1 :
((b - a) > fuzzyEpsilon ? -1 : 0);
}
以二進制實數表示十進制值是近似值,會導致各種奇怪的行爲。精度通常會隨着算術的進一步降低,特別是減去附近的值。然而,單獨的數值可以通過在比較之前舍入到最小數量的數字進行比較來清除。例如V = round(V * 1e14)/ 1e14將任意值V舍入爲14個十進制數字。兩個這樣的值可以放心地比較平等。 64位實數具有15.65的精度,因此四捨五入爲14位(或更少)提供了一些錯誤空間。
是的,乘法round()和除法序列很昂貴。但是,十進制是一種人機界面,通常用於無法容忍「有趣」算術的貨幣應用。錯誤通常比緩慢更糟糕。
我會測試不同之處:if((flOne - flTwo)
duDE
3.45不大於3.44?你爲什麼要讓他們平等? – ogzd
你可以使用*定點數學嗎?一個例子就是將浮點計量轉換爲固定點毫米。 –