我正在使用.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寄存器的精度。
+1有趣。我在我的機器上看到完全相同的症狀,並且在x86/anycpu之間切換會更改輸出。 – sisve 2010-10-25 21:23:09
您的最後一段不正確。 32位版本將**更加正確**,因爲它使用80位擴展精度x87 FPU,而64位版本將使用更快和更一致的SSE2。 – 2017-01-01 09:56:41
[x86和x64之間的浮點運算差異]的可能重複(http://stackoverflow.com/questions/22710272/difference-in-floating-point-arithmetics-between-x86-and-x64) – 2017-01-01 10:38:00