2013-04-18 51 views
9

當除法結果爲無限重複的數字時,數字顯然會被截斷以適應小數點的大小。所以像1/3這樣的東西變得像0.3333333333333333333。如果我們將這個數字乘以3,那麼我們得到類似於0.999999999999999999而不是1的數據,就像我們將得到的數據的真實值保存一樣。小數如何處理無限重複的數字?

這是從上小數MSDN文章的這一個代碼示例:

decimal dividend = Decimal.One; 
decimal divisor = 3; 
// The following displays 0.9999999999999999999999999999 to the console 
Console.WriteLine(dividend/divisor * divisor); 

當值0.9999999999999999999與1相等相比,這導致一個問題。沒有精度的損失,它們將是平等的,但當然在這種情況下,比較會導致錯誤。

人們通常如何處理這個問題?除了爲每個比較定義一些誤差外,是否還有更優雅的解決方案?

+0

@nathanhayfield看起來你錯過了這個問題的最後一句話。 –

+0

儘管如此,那*就是這樣做的一般方式,無論是在位置上,還是在函數內部都有空白的情況下,或者讓你指定一個(這在可讀性方面會更優雅,但概念相同)。(不要忘記,如果你曾經向用戶展示過結果,也可能會看到一些可讀的結果,沒有人願意看到他們欠$ 1.99999999999。是的,我已經看到過這種情況,好幾次。) – neminem

+2

這是一個古老而知名的問題在數字計算 –

回答

5

這是一個非常古老且衆所周知的數值計算問題。您已經表示您正在尋找一種解決方案,而不是爲每次比較定義一些誤差範圍。我想到的一種方法是首先在內存中構建數學表達式樹並最後進行計算。掌握這一點後,我們可以在進行計算之前使用一些已知規則進行一些簡化。規則,例如:在一小部分的分子和分母

  • 刪除相等數量的,如果他們不爲零
  • 數字的平方的平方根是多少本身
  • ...

因此,不要將1/3存儲在十進制/雙精度值(等於0.33333)中......我們可以存儲一個Fraction(1, 3)的實例。然後我們可以像這樣定義所有其他表達式來構建表達式而不是進行計算。最後,我們可以先用上面的規則簡化表達式,然後計算結果。

我在網上搜索了一下簡單地找到了圖書館來做到這一點,但還沒有找到。但我相信一些可以找到其他語言/平臺,甚至.NET。

請注意,上述方法最終只會產生更好的結果,但並不能解決數值計算本質固有的問題。

+0

像Waterloo Maple或Mathematica這樣的軟件包可以做到這一點課程。我不知道任何.NET庫。 –

+0

我找不到.NET庫,最後我只是用自己所需的基本功能做了自己的工作。 – GBleaney

1

歡迎來到浮點算術的痛苦。

你真正想要的,當然是理性的數字類和圖書館。下面是一個在C#中的一個開始,雖然我不知道它是(可能不是很)如何完成:

http://www.codeproject.com/Articles/88980/Rational-Numbers-NET-4-0-Version-Rational-Computin

有一些在C/C++,但同樣,不知道怎麼有用/完成它們。

對於浮點數:

查看一些資源。首先,David Goldberg的經典着作是「每個計算機科學家應該知道的關於浮點運算的知識」。以下是摘要:

浮點算法被許多人視爲深奧的主題。 這很令人驚訝,因爲浮點在計算機系統中無處不在:幾乎每種語言都有一個浮點數據類型;從PC到超級計算機的計算機具有浮點加速器;大多數編譯器將被要求編譯 時間的浮點算法; 幾乎每個操作系統都必須響應浮點異常 (如溢出)。 本文介紹了一個關於浮點的教程,這些教程對計算機系統的設計者有直接的 影響。它以浮點數 表示和舍入錯誤的背景開始,繼續討論IEEE浮點標準,並結合計算機系統構建者如何更好地支持浮點的示例。

您可以從多個地方下載的文件,無償的編輯版本:

此外,原本應該是容易在大磚頭建築,所有的書。全文引用爲

David Goldberg。 1991年。每個計算機科學家應該知道的關於浮點數的算術運算。 ACM Comput。監測網。 23,1(1991年3月),5-48。 DOI = 10.1145/103162.103163 http://doi.acm.org/10.1145/103162.103163

然後看看這些資源:

+0

Microsoft Solver Foundation隨附Rational類。 –

+0

@EricLippert:我不知道。謝謝! –

0

如果你有去我的方式commented然後將它存儲到數據庫中也不會成爲問題。你可以用分數類型在數據庫中存儲它。請參閱UDT。

2

如上所述,使用浮點數的計算結果必須「擬合」到浮點表示中。這就是爲什麼精確比較不是一個好主意 - 需要一些寬容。所以應該使用x == yMath.Abs(x - y) < tolerance