2014-03-28 40 views
10

我偶然發現了MS VS 2010構建x86和x64(都在同一臺64位機器上執行)之間的浮點算法差異。x86和x64之間浮點算術的區別

這是一個降低代碼示例:

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總是假的(d設置爲65.0在兩個版本)。 對於x64,變量bLarger2爲false,但在x86中爲true!

我很清楚浮點算術和四捨五入效應發生。我也知道,32位有時使用不同的指令進行浮動操作,而不是64位版本。但在這種情況下,我錯過了一些信息。

爲什麼bLarger1和bLarger2之間的差距在第一位?爲什麼它只出現在32位版本上?

Left: x86, Right: x64

+1

我的猜測是x86版本正在使用FPU寄存器,而x64正在使用SSE寄存器。但是您可能需要查看IL代碼以及機器代碼。 – Lev

+1

當然,x86是使用x87單元,而x64是使用SSE單元。但它並沒有真正解釋這種差異。他們都應該得到相同的答案。 @Oliver能否告訴我你是如何編譯代碼的,因爲我試圖在repro上失敗。對於我來說,這兩個bool對於x86和x64都是「虛假」的。 –

+0

好吧,現在我得到了一個repro! –

回答

16

在此表達的問題,鉸鏈:

bool bLarger2 = (a*c)<b; 

我看了看,沒有VS2010 VS2008下生成的代碼交手。對於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的操作都是以高於單精度的方式執行的。默認情況下,計算是以雙精度執行的。另一方面,上證所單位操作是純粹的單精度計算。

可以說服32位爲單位來執行所有計算,單精度精度是這樣的:

_controlfp(_PC_24, _MCW_PC); 

當您添加到您的32位程序,你會發現布爾值都設置爲false。

x87和SSE浮點單元的工作方式有一個根本性的區別。 x87單元對於單精度和雙精度類型都使用相同的指令。數據加載到x87 FPU堆棧中的寄存器中,並且這些寄存器始終是10個字節的Intel擴展。您可以使用浮點控制字來控制精度。但編譯器編寫的指令對該狀態一無所知。

另一方面,SSE單元對單精度和雙精度的操作使用不同的指令。這意味着編譯器可以發出完全控制計算精度的代碼。

因此,x87單位在這裏是壞人。你甚至可以試着說服你的編譯器發出SSE指令,即使是32位的目標。當然,當我在VS2013下編譯你的代碼時,我發現32位和64位目標都發出了SSE指令。

+0

有趣的是,所以我假設bLarger1和bLarger2的計算方式之間的差異是ALU的精度。對於bLarger2,將精度較高的結果保存在ALU中進行比較,而bLarger1將首先加載單精度值並對其進行比較。 –

+0

@OliverZendel正確 –

+0

嗯,既不改變「啓用增強指令集」,也不改變「浮點型號」導致不同的行爲(VS2010 x86); _controlfp做的伎倆,但我仍然好奇,如果有一個編譯器設置本身導致相同的行爲 –

-2

浮點操作總是不精確,並比較兩個浮點數如此接近(或等於)幾乎沒有返回正確的輸出。

浮點數在32位和64位機器上的存儲和處理方式不同(也可參見注釋)。如果我沒有記錯,VC 32位浮點數保存在堆棧中,FPU(浮點單元)處理它們,而64位機器上的浮點數可以存儲在專用寄存器(SSE)中,並使用CPU中的其他單元進行計算。

我沒有明確的來源我的答案,但請看看this pagethis.

+0

存儲沒有區別。這些是IEEE754浮點數。標準格式。 –

+0

@DavidHeffernan,它們以相同的方式存儲,但不同的位置是我想說的。 – Janman

+0

但是浮動不一定存儲在堆棧上。 x87單元有8個擴展精度浮點寄存器ST(0)到ST(7)的自己的寄存器堆棧。它們確實是專門的寄存器。上證所股有自己的專用寄存器。 –