相关疑难解决方法(0)

为什么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 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
Run Code Online (Sandbox Code Playgroud)

在打开或关闭JIT的两个平台上,结果都是一致的.

[编辑]

我对下面的答案并不完全满意,所以这里有一些我搜索的细节.

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

因此32位使用80位FPU寄存器,64位使用128位SSE寄存器.

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

[原理:此设计允许CLI为浮点数选择特定于平台的高性能表示,直到它们被放置在存储位置.例如,它可能能够在硬件寄存器中保留浮点变量,这些变量提供的精度比用户请求的更高.在分区I 69同时,CIL生成器可以通过使用转换指令强制操作遵守特定于语言的表示规则.最终理由]

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

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

.net c# math x86-64 32bit-64bit

11
推荐指数
1
解决办法
2064
查看次数

将float浮动到int,32位C的区别

我目前正在使用需要运行32位系统的旧代码.在这项工作中,我偶然发现了一个问题(出于学术兴趣),我想了解其原因.

如果对变量或表达式进行强制转换,似乎在32位C中从float转换为int的行为会有所不同.考虑该计划:

#include <stdio.h>
int main() {
   int i,c1,c2;
   float f1,f10;
   for (i=0; i< 21; i++)  {
      f1 = 3+i*0.1;
      f10 = f1*10.0;
      c1 = (int)f10;
      c2 = (int)(f1*10.0);
      printf("%d, %d, %d, %11.9f, %11.9f\n",c1,c2,c1-c2,f10,f1*10.0);
   }
}
Run Code Online (Sandbox Code Playgroud)

使用-m32修饰符直接在32位系统或64位系统上编译(使用gcc),程序的输出为:

30, 30, 0, 30.000000000 30.000000000
31, 30, 1, 31.000000000 30.999999046
32, 32, 0, 32.000000000 32.000000477
33, 32, 1, 33.000000000 32.999999523
34, 34, 0, 34.000000000 34.000000954
35, 35, 0, 35.000000000 35.000000000
36, 35, 1, 36.000000000 35.999999046
37, 37, 0, 37.000000000 37.000000477
38, …
Run Code Online (Sandbox Code Playgroud)

c casting 32-bit

11
推荐指数
2
解决办法
813
查看次数

128位到512位寄存器用于什么?

在查看x86/x64架构中的寄存器表之后,我注意到有128,256和512位寄存器的整个部分,我从未见过它们用于汇编或反编译的C/C++代码: XMM(0-15)表示128,YMM(0-15)表示256,ZMM(0-31)512.

做了一些挖后我所收集的是,你必须使用2个64位操作,以一个128位的数字进行的,而不是使用通用的数学,add,sub,mul,div操作.如果是这种情况,那么具有这些扩展寄存器集的用途究竟是什么,是否有任何汇编操作可以用来操作它们?

assembly sse x86-64 simd cpu-registers

7
推荐指数
1
解决办法
645
查看次数

64位浮点移植问题

我正在将我的应用程序从32位移植到64位.目前,代码在两种架构下编译,但结果不同.由于各种原因,我使用浮动而不是双打.我假设在一台机器上有一些从浮动到双重的隐式上转换而不是另一台机器.有没有办法控制这个,或者我应该寻找特定的陷阱?

编辑添加:

32位平台

 gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-33)
 Dual-Core AMD Opteron(tm) Processor 2218 HE
Run Code Online (Sandbox Code Playgroud)

64位平台

 gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3
 Intel(R) Xeon(R) CPU
Run Code Online (Sandbox Code Playgroud)

应用-mfpmath = 387有点帮助,在算法的1次迭代之后,值是相同的,但除此之外,它们再次失去同步.

我还应该补充一点,我关心的不是结果不一样,而是移植到64位平台已经发现了32位依赖,我不知道.

c c++ floating-point 64-bit portability

6
推荐指数
2
解决办法
5830
查看次数

浮点计算根据编译器而变化

当我运行完全相同的代码执行在Windows和Solaris上编译的完全相同的浮点计算(使用双精度)时,我得到的结果略有不同.

我知道由于舍入错误导致结果不准确.但是我希望舍入错误与平台无关,从而在两个平台上给出相同(略微不正确)的结果,但事实并非如此.

这是正常的,还是我的代码中还有其他问题?

c c++ floating-point

6
推荐指数
1
解决办法
1536
查看次数

性能影响长倍。为什么C会默认选择64位而不是硬件的80位?

具体来说,我谈论的是x87 PC架构和C编译器。

我正在编写自己的解释器,double数据类型背后的推理使我感到困惑。特别是在效率方面。有人可以解释为什么C选择了64位double而不是硬件本机80位double吗?又为什么硬件没有设置在80位double上呢?每种性能都有什么影响?我想使用80位double作为默认数字类型。但是编译器开发人员的选择让我担心这不是最佳选择。

  1. double在x86上仅短2个字节,为什么编译器long double默认不使用10个字节?
  2. 我可以举一个80位long doublevs所带来的额外精度的例子double吗?
  3. 为什么Microsoft long double 默认情况下禁用
  4. 就数量而言,long double典型的x86 / x64 PC硬件的差/慢多少?

floating-point performance x86 long-double visual-c++

5
推荐指数
1
解决办法
1489
查看次数