2009-12-02 71 views
4

當然,一個人永遠不能比較浮動,從平等的計算結果點值,但總是用一個小的公差,如:不Math.Round(雙,十進制)總是返回一致的結果

double value1 = ... 
double value2 = ... 
if (Math.Abs(value1 - value2) < tolerance * Math.Abs(value1)) 
{ 
    ... values are close enough 
} 

但如果我使用Math.Round,我可以始終確保結果值是一致的,也就是說,即使四捨五入的值是無法完全用double表示的值,下面的Assert也會成功嗎?

public static void TestRound(double value1, double value2, int decimals) 
{ 
    double roundedValue1 = Math.Round(value1, decimals); 
    double roundedValue2 = Math.Round(value2, decimals); 

    string format = "N" + decimals.ToString(); 
    if (roundedValue1.ToString(format) == roundedValue2.ToString(format)) 
    { 
     // They rounded to the same value, was the rounding exact? 
     Debug.Assert(roundedValue1 == roundedValue2); 
    } 
} 

如果不是,請提供一個反例。

編輯

感謝astander通過,證明結果蠻力產生一個反例是不是在一般情況下「保持一致」。這個反在舍入結果16個顯著數字 - 因此在縮放時也無法以同樣的方式:

 double value1 = 10546080000034341D; 
     double value2 = 10546080000034257D; 
     int decimals = 0; 
     TestRound(value1, value2, decimals); 

不過,我也很想在一個更加數學解釋。對於任何更多的數學Stackoverflowers誰可以做以下任何的獎金upvotes:

  • 找到一個反例,其中四捨五入的結果少於16顯著位。

  • 確定一個數值範圍的量,舍入的結果永遠是「一致的」如本文所定義(例如所有值,其中的數字顯著在舍入的結果的數量是< N)的。

  • 提供一種生成反例的算法方法。

+0

Eric Lippert撰寫了一篇關於浮點數的文章,他們可能會闡述一些光明.. http://blogs.msdn.com/ericlippert/ archive/tags/Floating + Point + Arithmetic/default.aspx – flesh

回答

2

好的,這似乎是一個非常技術性的問題,所以我認爲蠻力可能會告訴我們。

我嘗試以下

public static void TestRound(double value1, double value2, int decimals) 
{ 
    double roundedValue1 = Math.Round(value1, decimals); 
    double roundedValue2 = Math.Round(value2, decimals); 

    string format = "N" + decimals.ToString(); 
    if (roundedValue1.ToString(format) == roundedValue2.ToString(format)) 
    { 
     // They rounded to the same value, was the rounding exact? 
     if (roundedValue1 != roundedValue2) 
     { 
      string s = ""; 
     } 
    } 
} 
private void button1_Click(object sender, EventArgs e) 
{ 
    for (double d = 0, inc = .000001; d < 1000; d += inc) 
     for (int p = 0; p <= 15; p++) 
      TestRound(Math.Pow(Math.Pow(d, inc), 1/inc), d, p); 
} 

我放置在 「字符串s = 」「 斷點;」到chcek當它進入這個部分,

,它具有以下值

value1 = 1.0546080000034341 
value2 = 1.0546080000034257 
decimals = 15 
roundedValue1 = 1.0546080000034339 
roundedValue2 = 1.0546080000034259 
roundedValue1.ToString(format) = 1.054608000003430 
roundedValue2.ToString(format) = 1.054608000003430 

我想這就是你要找的答案進入?

如果不是,請讓我知道,所以我可以測試更多。

+0

是我還是'ToString(「N15」)'這個比'Round'中的缺陷還要多?這些雙精度值在小數點後15位取整爲不同的值,但是'ToString(「N15」)'將它們舍入到14位小數位加0。 – Rawling

2

雖然浮點計算精度有限,因此不精確,但它們是確定性的。因此,如果對相同的值以相同的順序使用相同的計算,則應始終得到相同的結果。因此,對相同的值使用相同的舍入方法會得到相同的結果。

浮點計算的問題是兩個不同計算的結果在數學上給出了相同的結果(e.q.Sqrt(x)*Sqrt(x)==x)由於計算內的舍入誤差,最有可能會有所不同

+0

當然,但我正在討論在兩個不同的*值上使用相同的舍入方法,這些值將舍入到「相同」結果中。看見阿斯達的回答。 – Joe