为什么Math.Exp在32位和64位之间给出不同的结果,但输入相同,硬件相同
我正在使用.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寄存器的精度。
是舍入错误,它实际上不是相同的硬件。 32位版本针对不同的指令集和寄存器大小。
这很有趣 - 你是说有一套不同的FPU指令?无可否认,我不知道Math.Exp是如何实现的,无论是一个FPU指令还是多个指令。而且我会认为FPU寄存器在两个平台上都是相同的,因为我使用'double'类型。 – Yoshi 2010-10-25 21:34:08
我不知道.NET实现或x64 fpu的minutae,但我不会期望它们是完全相同的。你也正在从int转换为double,这引入了一个错误。 – winwaed 2010-10-25 22:09:38
我打算将其标记为答案,因为我认为它提供了最详细的信息。我在这个URL上找到了更多的信息,它解释了32位.NET使用80位FPU寄存器,而64位.NET使用128位SSE寄存器:http://www.manicai.net/comp/调试/ fpudiff/ – Yoshi 2010-10-26 00:37:13
使用Double类型时,您将得到舍入误差,因为二进制中的分数非常快速地变大。如果您使用Decimal类型,它可能会有所帮助。
I (想)我明白,但在相同硬件上的相同输入上发生的舍入错误应该在leas不一致吧?还是由于其他因素而无法保证? – Yoshi 2010-10-25 21:16:23
+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