x86和x64之间的浮点算术的差异

Oli*_*del 10 c c++ floating-point 64-bit visual-studio-2010

我偶然发现了在x86和x64的MS VS 2010版本之间完成浮点算术的方式不同(两者都在同一台64位机器上执行).

这是一个简化的代码示例:

float a = 50.0f;
float b = 65.0f;
float c =  1.3f;
float d = a*c;
bool bLarger1 = d<b;
bool bLarger2 = (a*c)<b;
Run Code Online (Sandbox Code Playgroud)

布尔bLarger1始终为false(在两个版本中d都设置为65.0).变量bLarger2对于x64为false,但对于x86为true!

我很清楚浮点算术和圆角效应正在发生.我也知道32位有时使用不同的指令进行浮动操作而不是64位构建.但在这种情况下,我错过了一些信息.

为什么bLarger1和bLarger2之间首先存在差异?为什么它只出现在32位版本上?

左:x86,右:x64

Dav*_*nan 17

问题取决于这个表达:

bool bLarger2 = (a*c)<b;
Run Code Online (Sandbox Code Playgroud)

我查看了VS2008下生成的代码,没有手持VS2010.对于64位代码是:

000000013FD51100  movss       xmm1,dword ptr [a] 
000000013FD51106  mulss       xmm1,dword ptr [c] 
000000013FD5110C  movss       xmm0,dword ptr [b] 
000000013FD51112  comiss      xmm0,xmm1 

对于32位代码是:

00FC14DC  fld         dword ptr [a] 
00FC14DF  fmul        dword ptr [c] 
00FC14E2  fld         dword ptr [b] 
00FC14E5  fcompp           

因此,在32位下,计算在x87单元中执行,而在64位下,它由x64单元执行.

这里的区别在于x87操作都是以高于单精度的方式执行的.默认情况下,执行计算以获得双精度.另一方面,SSE单元操作是纯单精度计算.

你可以说服32位单元执行所有计算到单精度精度,如下所示:

_controlfp(_PC_24, _MCW_PC);
Run Code Online (Sandbox Code Playgroud)

当您将其添加到32位程序时,您会发现布尔值都设置为false.

x87和SSE浮点单元的工作方式有根本区别.x87单元对单精度和双精度类型使用相同的指令.数据被加载到x87 FPU堆栈的寄存器中,这些寄存器总是10字节Intel扩展.您可以使用浮点控制字来控制精度.但编译器编写的指令不了解该状态.

另一方面,SSE单元对单精度和双精度的操作使用不同的指令.这意味着编译器可以发出完全控制计算精度的代码.

所以,x87单元在这里是坏人.您可以尝试说服编译器发出SSE指令,即使对于32位目标也是如此.当然,当我在VS2013下编译你的代码时,我发现32位和64位目标都发出了SSE指令.

  • @OliverZendel没有可以更改控制字的编译器设置.这是一个运行时属性,因此必须在运行时进行管理.这是一个完整的雷区FWIW,模块左右,中心与控制字拧紧.使用`/ arch:SSE2`编译,你将避免所有x87的痛苦.但是您的程序只能在具有SSE2单元的机器上运行. (3认同)