2011-10-26 26 views
2

下面的函數計算32位的浮點值的絕對值:我可以創建一個具有傳遞給C++函數的形式參數的聯合?

__forceinline static float Abs(float x) 
{ 
    union { 
     float x; 
     int a; 
    } u; 
    //u.x = x; 
    u.a &= 0x7FFFFFFF; 
    return u.x; 
} 

工會ü在函數聲明保持變量x,其是從被作爲函數參數傳遞的X不同。有什麼辦法可以用函數的參數創建一個聯合 - x?

任何原因上面的功能與未註釋的行執行時間比這更長?

__forceinline float fastAbs(float a) 
{ 
    int b= *((int *)&a) & 0x7FFFFFFF; 
    return *((float *)(&b)); 
} 

我想弄清楚最好的方式,以儘可能少的讀取/寫入到內存中的浮點數值。

+2

'std :: abs'相對於您的版本有多長? – avakar

+3

btw ...爲什麼不使用std :: fabs?因爲這將使用適當的CPU指令集來計算絕對值(在intel架構上它是FABS),這比上面做的任何事情都要快得多。 –

+0

Ahmed Masud:你確定嗎?我現在會測試它。 ...嗯,不完全明白爲什麼,但它出來簡單的晶圓廠功能是最快的:晶圓廠 - 0.922311,fastAbs(從上面) - 0.935108,吸收(也從上面) - 0.937011,絕對雙 - 0.936235。我很好奇這一點... – Vadim

回答

2

看看在發佈模式下編譯的代碼的反彙編,差異是非常明顯的! 我刪除了內聯,並使用了兩個虛函數,以使編譯器不會優化太多,讓我們展示差異。

這是第一個功能。

013D1002 in   al,dx 
      union { 
       float x; 
       int a; 
      } u; 
      u.x = x; 
013D1003 fld   dword ptr [x] // Loads a float on top of the FPU STACK. 
013D1006 fstp  dword ptr [x] // Pops a Float Number from the top of the FPU Stack into the destination address. 
      u.a &= 0x7FFFFFFF; 
013D1009 and   dword ptr [x],7FFFFFFFh // Execute a 32 bit binary and operation with the specified address. 
      return u.x; 
013D1010 fld   dword ptr [x] // Loads the result on top of the FPU stack. 
     } 

這是第二個功能。

013D1020 push  ebp      // Standard function entry... i'm using a virtual function here to show the difference. 
013D1021 mov   ebp,esp 
      int b= *((int *)&a) & 0x7FFFFFFF; 
013D1023 mov   eax,dword ptr [a]   // Load into eax our parameter. 
013D1026 and   eax,7FFFFFFFh    // Execute 32 bit binary and between our register and our constant. 
013D102B mov   dword ptr [a],eax   // Move the register value into our destination variable 
      return *((float *)(&b)); 
013D102E fld   dword ptr [a]    // Loads the result on top of the FPU stack. 

在第一種情況下,浮點運算的數量和FPU堆棧的使用量更大。 這些函數正在執行你所要求的內容,所以並不奇怪。 所以我期望第二個函數更快。

現在...刪除虛擬和內聯的東西有點不同,很難在這裏編寫反彙編代碼,因爲編譯器當然做得很好,但我再說一遍,如果值不是常量,編譯器將在第一次使用更多浮點操作功能。 當然,整數運算比浮點運算更快。

你確定直接使用math.h abs函數比你的方法慢嗎? 如果內嵌正確,abs函數將會執行此操作!

00D71016 fabs 

微優化像這樣的很難在長碼看,但如果你的函數被調用浮點運算的長鏈,晶圓廠將更好地工作,因爲值將是已經在FPU堆棧或SSE註冊! abs會更快,更好地被編譯器優化。

您無法測量在一段代碼中運行循環的優化的性能,您必須瞭解編譯器如何在實際代碼中混合在一起。

+1

我測試了現在的晶圓廠功能,它出來更快。看起來我很笨拙地忽略了「事實」,即手動設置最重要的位的速度比晶圓廠快,但事實並非如此。我現在將刪除我的'fastAbs'功能並將其替換爲晶圓廠。謝謝你們的好解釋! – Vadim

+0

我也在我的應用程序中對它進行了測試,實際上代碼運行速度更快!很高興我問了這個問題,因爲排序一些不必要的東西並不好。 – Vadim

5

對於第一個問題,我不確定爲什麼你不能只是你想要的任務。編譯器會做任何可以完成的優化。

在你的第二個示例代碼。你違反嚴格的別名。所以它是不一樣的。

至於爲什麼它的速度較慢:

這是因爲今天的CPU往往有獨立的整數和浮點單元。通過這樣的打字,你可以強制將這個值從一個單位移到另一個單位。這有開銷。 (這往往是通過記憶完成的,所以你有額外的負載和存儲。)

在第二個片段:a這是原本在浮點單元(或者是的x87 FPU或SSE寄存器),需要被移入通用寄存器以應用掩碼0x7FFFFFFF。然後它需要被移回。

在第一個片段中:編譯器可能足夠聰明,可以將a直接加載到整數單元中。所以你在第一階段繞過了FPU。我不是100%肯定的,直到你向我們展示了程序集,它還將在很大程度上取決於參數是從一個寄存器還是堆棧中開始,而且輸出是否被另一個浮點立即使用操作)。

+0

第一個版本也是UB,你只能讀最後寫入的聯合成員(除非在C++ 11中改變了)。 – avakar

+0

我知道在C99中,你可以通過工會來完成。但我不確定C++ 11。 – Mysticial

相關問題