簡體   English   中英

划分雙打時C#精度損失

[英]C# loss of precision when dividing doubles

我知道這已經一次又一次地討論了,但是我似乎無法得到一個一步一步的雙重划分的最簡單的例子,導致C#的預期的,不完整的結果 - 所以我想知道是否也許有一些編譯器標志或其他奇怪的我沒有想到的。 考慮這個例子:

double v1 = 0.7;
double v2 = 0.025;
double result = v1 / v2;

當我在最后一行之后斷開並在VS調試器中檢查它時,“result”的值是27.999999999999996。 我知道我可以通過更改為“十進制”來解決它,但在周圍程序的情況下這是不可能的。 像這樣的兩個低精度雙倍不能分成28的正確值是不奇怪的? 對Math.Round來說唯一的解決方案是結果嗎?

像這樣的兩個低精度雙倍不能分成28的正確值是不奇怪的?

不,不是真的。 double類型中,0.7和0.025都不能精確表示。 涉及的確切價值是:

0.6999999999999999555910790149937383830547332763671875
0.025000000000000001387778780781445675529539585113525390625

現在你感到驚訝的是,該部門並沒有給出28分? 垃圾進垃圾出...

如你所說,正確表示十進制數的正確結果是使用decimal 如果你的程序的其余部分使用了錯誤的類型,那只意味着你需要解決更高的問題:獲得錯誤答案的成本,或者更改整個程序的成本。

如果你正在處理floatdouble ,精度總是一個問題。

它是計算機科學中的一個已知問題,每種編程語言都受其影響。 為了最大限度地減少這些與舍入主要相關的錯誤,我們專門研究了一個完整的數值分析領域。

例如,讓我們采取以下代碼。

你會期待什么?

你會期望答案是1 ,但事實並非如此,你會得到0.9999907

        float v = .001f;            
        float sum = 0;
        for (int i = 0; i < 1000; i++ )
        {
            sum += v;
        }

它與double數字的“簡單”或“小”無關。 嚴格地說, 0.70.025都不能存儲為計算機內存中的那些數字,因此如果你的精確度很高,那么對它們進行計算可能會提供有趣的結果。

所以是的,使用decimal或圓形。

通過類比來解釋這個:

想象一下,你在基數3工作。在基數3中,0.1是(十進制)1/3,或0.333333333'。

因此,您可以在基數3中精確表示1/3(十進制),但在嘗試以十進制表示時會出現舍入錯誤。

好吧,你可以用一些十進制數得到完全相同的東西:它們可以用十進制精確表示,但它們不能用二進制表示; 因此,你會得到舍入錯誤。

簡短回答你的第一個問題:不,這並不奇怪。 浮點數是實數的離散近似值,這意味着當您進行算術運算時,舍入誤差將傳播和縮放。

Theres是一個稱為數值分析的整個數學領域,它基本上處理了在使用這種近似時如何最小化誤差。

這是通常的浮點不精確。 並非每個數字都可以表示為double,並且這些次要表示不准確性會加起來。 這也是你不應該將雙打與精確數字進行比較的原因。 我只是測試了它, result.ToString() double.ToString()顯示28 (也許某種舍入發生在double.ToString() ?)。 result == 28雖然返回了false 並且(int)result返回27 所以你只需要期待那樣的不精確。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM