C# · 12月 27, 2021

c# – 为什么Math.Exp在32位和64位之间提供不同的结果,具有相同的输入,相同的硬件

我正在使用.NET 2.0与PlatformTarget x64和x86.我给Math.Exp输入相同的输入数字,并在任一平台上返回不同的结果.

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 conversionDebug.Assert(d.ToString(“G17”) == “-0.0068846153846153849” && BitConverter.DoubleToInt64Bits(d) == -4648784593573222648L); // true on both 32 & 64 bitdouble 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/说:

So 32-bit is using the 80-bit FPU registers,64-bit is using the 128-bit SSE registers.

而CLI标准表示,如果硬件支持双精度可以用更高的精度表示:

[Rationale: This design allows the CLI to choose a platform-specific high-performance representation for
floating-point numbers until they are placed in storage locations. For example,it might be able to leave
floating-point variables in hardware registers that provide more precision than a user has requested. At the
Partition I 69
same time,CIL generators can force operations to respect language-specific rules for representations through
the use of conversion instructions. end rationale]

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf(12.1.3处理浮点数据类型)

我认为这是这里发生的一切,因为Double的标准精度为15位,结果不同. 64位Math.Exp结果更精确(它有一个额外的数字),因为内部的64位.NET正在使用比32位.NET使用的FPU寄存器更精确的FPU寄存器.

解决方法 是四舍五入的错误,它实际上是不一样的硬件. 32位版本的目标是一组不同的指令和寄存器大小.