2009-10-21 55 views
3

我正在執行一些數據類型轉換,我需要將uint,long,ulongdecimal表示爲IEEE 754雙浮點值。我希望能夠在執行轉換之前檢測IEEE 754數據類型是否不能包含該值。如何測試數值轉換是否會改變數值?

一個蠻力解決方案將圍繞一個演員包裹試試抓,以加倍尋找OverflowException。通過CLR documentation中的某些內容進行閱讀意味着某些轉換隻是在無任何例外的情況下默默改變了該值。

有沒有任何傻瓜證明的方式來做這個檢查?我正在尋求完整性,以便於實施。我有一種感覺,我會仔細閱讀IEEE 754規範並仔細檢查matissa和指數...

我應該補充說,我是大多數與準確表示整數有關,並且浮動損失點精度是次要問題(但仍值得考慮)。

編輯: Int32能夠完全表示爲IEE-754。此外,Decimal數據類型也是問題的一部分。

重要更新:如果你指的是這個問題,你也應該看這個問題:IEEE-754 Double (64-bit floating point) vs. Long (64-bit Integer) Revisited

它指出在回答一個缺陷,其中一些非常大的價值,也能夠通過IEEE準確表示-754。雖然這可能意味着該值將正確往返,爲我的原始目的(它是否會往返JavaScript)它不會。

此外,似乎CLRs System.Double類型中存在一個錯誤,因爲它沒有正確地允許這些值往返。

+0

如果您想避免溢出,您可以在轉換之前檢查您的值是否在目標類型的MinValue和MaxValue內。如果你想避免精度問題,不要使用浮點數。 – Guillaume 2009-10-21 15:38:50

回答

9

簡單的解決方案可能是這樣的(如果x是一個int):

if ((int)(double)x != x) { 
    // won't convert 
} else { 
    // will convert 
} 

等長等

(雙)x將x轉換從int到雙倍。 (int)然後再將其轉換回來。所以(int)(double)x將int轉換爲double,然後返回。本質上,代碼檢查轉換爲double是可逆的(因此double可以存儲int的確切值)。

+0

我不知道爲什麼這是downvoted - 這似乎是最簡單,最明顯正確的解決方案給我。 – 2009-10-21 15:33:45

+0

+1 - 這是一個簡單的答案,你可能希望把「如果x是一個整數」的粗體澄清,因爲它很容易被忽略。 – 2009-10-21 15:35:49

+0

您可能想要解釋(int)(double)是如何工作的,因爲這不是一個普通的演員,並且除了Jon Skeet的評論外,可能會認爲它不起作用。 – 2009-10-21 15:38:45

1

這主要取決於您使用的數字範圍。只要你的數字在15位以內(對於double),你應該對整個數字保持安全。

基本上,你需要考慮的是有效位數。所以只要你的數字小於有效數字限制,它​​就會保持精確;如果它變大,你將失去精度(即使這些是整數)。

所以只要你的號碼是< 2^53,你通常是好的。

1

IEEE 754 Double對於尾數有52位,而你正在轉換爲integer/long所以它很容易測試。如果您的整數消耗少於52位,那麼它應該可以無問題地轉換爲IEEE 754 double。

我認爲(我知道肯定在Java的情況下,但不是C#和懶惰檢查)int是32位和長是64位。所以肯定int可以在沒有任何問題的情況下符號和不符號。

對於ulong,只要所有高於第52位的位都像((aULong & & 0xFFF0000000000000)== 0)。

長期以來,您必須將其注意力納入考慮範圍。由於Long是第二補碼,但IEEE754不是(只有負位),它認爲將負長變爲正值(* -1)並檢查爲正值是安全的。所以,如果多頭爲負,則首先計入-1(對於正數不做任何事情)。然後,檢查它像ulong。

希望這會有所幫助。