2010-10-25 63 views
10

我正在使用.NET 2.0與PlatformTarget x64和x86。我給Math.Exp提供了相同的輸入數字,並在任一平臺中返回不同的結果。爲什麼Math.Exp在32位和64位之間給出不同的結果,但輸入相同,硬件相同

MSDN說你不能依賴文字/解析的Double來表示平臺之間的相同數字,但我認爲使用Int64BitsToDouble可以避免這個問題,並保證兩個平臺上的Math.Exp輸入相同。

我的問題是爲什麼結果不同?我本來認爲:

  • 輸入被存儲在相同的方式(雙/ 64位精度)
  • 的FPU會做相同的計算而不管處理器的位數
  • 的輸出被存儲在以同樣的方式

我知道我應該不是一般的15/17位之後的浮點數比較,但我感到困惑這裏的不一致之處看起來像在同一硬件上相同的操作。

任何人都知道引擎蓋下發生了什麼?

double d = BitConverter.Int64BitsToDouble(-4648784593573222648L); // same as Double.Parse("-0.0068846153846153849") but with no concern about losing digits in conversion 
Debug.Assert(d.ToString("G17") == "-0.0068846153846153849" 
    && BitConverter.DoubleToInt64Bits(d) == -4648784593573222648L); // true on both 32 & 64 bit 

double exp = Math.Exp(d); 

Console.WriteLine("{0:G17} = {1}", exp, BitConverter.DoubleToInt64Bits(exp)); 
// 64-bit: 0.99313902928727449 = 4607120620669726947 
// 32-bit: 0.9931390292872746 = 4607120620669726948 

在JIT打開或關閉的平臺上,結果是一致的。

[編輯]

我並不完全滿意,低於所以這裏的答案是從我的搜索一些更多的細節。

http://www.manicai.net/comp/debugging/fpudiff/說:

所以32位是使用80位的FPU寄存器,64位是使用128位的SSE寄存器。

和CLI標準說,雙打能夠以更高的精度,如果硬件支持的話表示:

[理由:這種設計允許CLI選擇一個特定於平臺的高性能表現爲 浮點數直到它們被放置在存儲位置。例如,它可能會將浮點變量保留在硬件寄存器中,提供比用戶要求的更高的精度。在同一時間,CIL生成器可以強制操作通過 使用轉換指令來遵守語言特定的表示規則。最終理由]

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf(浮點數據類型12.1.3處理)

我想這就是發生在這裏,因爲雙的精度標準15位後的不同結果。 64位Math.Exp結果更精確(它有一個額外的數字),因爲內部64位.NET使用FPU寄存器的精度高於32位.NET使用的FPU寄存器的精度。

+0

+1有趣。我在我的機器上看到完全相同的症狀,並且在x86/anycpu之間切換會更改輸出。 – sisve 2010-10-25 21:23:09

+1

您的最後一段不正確。 32位版本將**更加正​​確**,因爲它使用80位擴展精度x87 FPU,而64位版本將使用更快和更一致的SSE2。 – 2017-01-01 09:56:41

+1

[x86和x64之間的浮點運算差異]的可能重複(http://stackoverflow.com/questions/22710272/difference-in-floating-point-arithmetics-between-x86-and-x64) – 2017-01-01 10:38:00

回答

3

是舍入錯誤,它實際上不是相同的硬件。 32位版本針對不同的指令集和寄存器大小。

+1

這很有趣 - 你是說有一套不同的FPU指令?無可否認,我不知道Math.Exp是如何實現的,無論是一個FPU指令還是多個指令。而且我會認爲FPU寄存器在兩個平臺上都是相同的,因爲我使用'double'類型。 – Yoshi 2010-10-25 21:34:08

+0

我不知道.NET實現或x64 fpu的minutae,但我不會期望它們是完全相同的。你也正在從int轉換爲double,這引入了一個錯誤。 – winwaed 2010-10-25 22:09:38

+1

我打算將其標記爲答案,因爲我認爲它提供了最詳細的信息。我在這個URL上找到了更多的信息,它解釋了32位.NET使用80位FPU寄存器,而64位.NET使用128位SSE寄存器:http://www.manicai.net/comp/調試/ fpudiff/ – Yoshi 2010-10-26 00:37:13

3

使用Double類型時,您將得到舍入誤差,因爲二進制中的分數非常快速地變大。如果您使用Decimal類型,它可能會有所幫助。

+0

I (想)我明白,但在相同硬件上的相同輸入上發生的舍入錯誤應該在leas不一致吧?還是由於其他因素而無法保證? – Yoshi 2010-10-25 21:16:23

相關問題