2012-05-28 62 views
2

什麼是可以表示\轉換爲小數的最大double值?Convert.ToDecimal(double x) - System.OverflowException

該值如何導出 - 請舉例。

更新

由於可轉換爲十進制的雙重最大值,我希望能夠往返雙爲十進制,然後再回來。然而,如@ Jirka的回答中給出一個像(2^52)-1這樣的數字,這是行不通的。例如:

Test] 
    public void round_trip_double_to_decimal() 
    { 
     double maxDecimalAsDouble = (Math.Pow(2, 52) - 1); 

     decimal toDecimal = Convert.ToDecimal(maxDecimalAsDouble); 

     double toDouble = Convert.ToDouble(toDecimal); 

     //Fails. 
     Assert.That(toDouble, Is.EqualTo(maxDecimalAsDouble)); 
    } 
+0

我不確定是否可以有任何最大值,因爲這樣的一些浮點數不能用double精確表示,並且存在精度的損失,不需要在更高的水平,因此 – V4Vendetta

回答

4

-9,007,199,254,740,992和9,007,199,254,740,991之間的所有整數都可以用雙精度表示。(請繼續閱讀)

上限值推導爲2^53 - 1。如果你原諒我的十六進制語法,它的內部表示就像(0x1.fffffffffffff * 2^52)。

在此範圍之外,如果它們是2的冪的倍數,則許多整數仍可以精確地表示。

任何可以精確地表示將因此9,007,199,254,740,991 * (2^1023),比Decimal.MaxValue甚至更​​高,但是這是一個毫無意義的事實,因爲該值不刻意去改變,例如,當你在減去1的最大整數算術。

根據評論和進一步的研究,我添加了C#的.NET和Mono實現的相關信息,這些實現將您和我可能想要創建的大多數結論進行相關。

  • Math.Pow似乎並不保證任何具體的準確性,它似乎提供一點或比什麼double可以代表兩個少。這對於浮點函數來說並不太令人意外。英特爾浮點硬件沒有指數運算指令,我期望計算涉及指令,其中間結果會失去一些精度。如果需要整體精度,可以使用BigInteger.Pow

  • 但是,即使是(decimal)(double)9007199254740991M也會導致往返行程違規。然而,這次是known bug,這直接違反了C#規範的第6.2.1節。有趣的是,即使在Mono 2.8中我也看到了同樣的錯誤。 (引用的來源表明,這種轉換錯誤可以值較低連撞。)

  • 雙擊文字是那麼圓,但還是有一點:9007199254740991D打印出來作爲9007199254740990D。當解析字符串文字時(在上下限根據「小數點後的第一個零」收斂到相同的double值之前),這是內部乘法的僞像。這又違反了C#規範,這次是第9.4.4.3節。

  • 不像C,C#有沒有十六進制浮點文字,所以我們不能避免10乘以任何其他語法,也許除了通過DecimalBigInteger去,如果這些只提供了準確的轉換操作符。我還沒有測試BigInteger

  • 上面幾乎可以讓你想知道C#是否沒有發明自己的精確度較低的浮點格式。不,第11.1.6款提及64位IEC 60559表示。所以上面的確是bug。

所以,最後,你應該能夠在雙重精確,以適應甚至9007199254740991M,但它是相當大的挑戰在地方獲得的價值!

的道德故事的是,傳統的信念,「算術應該只比數據和預期的結果更精確」是錯誤的,因爲this famous article演示(第36頁),儘管在不同的情況下編程語言。

除非必須,否則不要將整數存儲在浮點變量中。

+0

你可能是對的:OP很可能意味着「完全代表」,而不會在他的問題中說出來。 – dasblinkenlight

+0

@Jirka因此,如果「2^52-1」的上限可以預期,我可以將雙打轉換爲小數,然後返回到該範圍內的雙打,並且所得到的double將相當於輸入double,即雙打往返? –

+0

@chibacity - 絕對。 –

相關問題