x86和x64之间的浮点算术的差异
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了x86和x64之间的浮点算术的差异相关的知识,希望对你有一定的参考价值。
我偶然发现了在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;
布尔bLarger1始终为false(在两个版本中d都设置为65.0)。变量bLarger2对于x64为false,但对于x86为true!
我很清楚浮点算术和圆角效应正在发生。我也知道32位有时使用不同的指令进行浮动操作而不是64位构建。但在这种情况下,我错过了一些信息。
为什么bLarger1和bLarger2之间首先出现差异?为什么它只出现在32位版本上?
问题取决于这个表达:
bool bLarger2 = (a*c)<b;
我查看了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);
当您将其添加到32位程序时,您会发现布尔值都设置为false。
x87和SSE浮点单元的工作方式有根本区别。 x87单元对单精度和双精度类型使用相同的指令。数据被加载到x87 FPU堆栈的寄存器中,这些寄存器总是10字节Intel扩展。您可以使用浮点控制字来控制精度。但编译器编写的指令不了解该状态。
另一方面,SSE单元对单精度和双精度的操作使用不同的指令。这意味着编译器可以发出完全控制计算精度的代码。
所以,x87单元在这里是坏人。您可以尝试说服编译器发出SSE指令,即使对于32位目标也是如此。当然,当我在VS2013下编译你的代码时,我发现32位和64位目标都发出了SSE指令。
浮点运算总是不精确的,比较两个浮点数这个接近(或相等)几乎从不返回正确的输出。
浮点数在32位和64位计算机上的存储和处理方式不同(也有注释建议)。如果我没记错的话,在VC中32位浮点数保存在堆栈中,FPU(浮点单元)处理它们,而64位机器上的浮点数可以存储在专用寄存器(SSE)中,并使用CPU中的其他单位计算。
我的答案没有明确的来源,但请查看this page或this.
以上是关于x86和x64之间的浮点算术的差异的主要内容,如果未能解决你的问题,请参考以下文章
模块计算机类型“X86”与目标计算机类型“x64”冲突,用的是vs2010