2017-10-09 27 views
2

我的團隊正在使用將貨幣值暴露爲C#浮點加倍的財務軟件。偶爾,我們需要比較這些值,看看它們是否等於零,或者是否落在特定的限制之下。當我注意到這個邏輯出現意外的行爲時,我很快就瞭解了浮點雙精度所固有的舍入誤差(例如1.1 + 2.2 = 3.3000000000000003)。到目前爲止,我主要使用C#小數來表示貨幣值。爲浮點比較選擇一個Epsilon值

我的團隊決定使用epsilon值方法解決此問題。基本上,當你比較兩個數字時,如果這兩個數字之間的差值小於ε,那麼它們被認爲是相等的。我們實施以類似的方式這種方式爲下面的文章中描述: https://www.codeproject.com/Articles/383871/Demystify-Csharp-floating-point-equality-and-relat

我們面臨的挑戰已經確定小量適當的值。我們的貨幣值在小數點右側最多可以有3位數字(比例= 3)。這意味着我們可以使用的最大epsilon是.0001(任何更大的數字和第三位被忽略)。由於epsilon的值應該很小,我們決定將它移出一個小數點到.00001(爲了安全起見,你可以說)。 C#雙精度爲at least 15 digits,所以我相信如果小數點左邊的數字小於或等於10位數(15 - 5 = 10,其中5是小數位數爲在小數點右側)。用10位數字,我們可以將數值表示爲數十億,最高可達9,999,999,999.999。我們可能有數以億計的數字,但我們並不期望達到數十億,所以這個限制應該足夠了。

我選擇epsilon的這個值的理由是正確的嗎?我發現了很多討論這種方法的資源,但我找不到提供選擇epsilon指導的許多資源。

+2

我認爲使用正常的,甚至DP,IEEE754不是一個偉大的財務計算思路。感知的智慧是使用C#的[decimal](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/decimal)類型;你考慮過這個嗎? –

+0

@IsaacWoods我正在爲現成的財務軟件編寫插件代碼,所以我無法控制它正在使用的數據類型。我曾考慮將double值轉換爲小數,但如果double已經包含舍入錯誤,它只會被複制到小數點。 –

+1

由於經歷了一些痛苦的經歷,從一位經理告訴我說:「你永遠不會讀200多張打卡。「,」我們預計不會進入數十億「這一形式的條款讓我非常緊張,你將如何執行這一限制?如果存在一段時間的通貨膨脹,會發生什麼情況?你以一家大型銀行作爲客戶?您的代碼與其他貨幣一起使用? –

回答

2

你的推理看起來很合理,但正如你已經發現它是一個複雜的問題。您可能想要閱讀What Every Computer Scientist Should Know About Floating-Point Arithmetic。您使用64位雙打確實有一個精度爲15位的至少。但是,您還需要驗證輸入,因爲浮點數可以包含Nan,+/- Infinity,負數零以及比15位十進制數字大得多的「範圍」。如果某人給你的圖書館賦予了一個像1.2E102這樣的值,你應該處理它還是將其視爲超出範圍?同樣值很小。垃圾進入,垃​​圾出來,但如果你的代碼檢測到垃圾的「味道」並且至少記錄了垃圾,它可能會很好。

您可能還想考慮提供一個屬性來設置精度以及不同形式的舍入。這在很大程度上取決於您正在使用的規格。您可能還想確定這些值是否可以代表美元以外的貨幣(1美元目前> 112日元)。

長和短的選擇你的需求下一個數字(因此小數點右邊的四位數字)你的epsilon是健全的,並給你一個數字用於一致的四捨五入。否則10.0129美元和10.0121美元將是平等的,但他們的總額將是20.025美元,而不是20.024美元......會計師喜歡「腳」的東西。