簡體   English   中英

我可以使用傳遞給C ++函數的形式參數創建聯合嗎?

[英]Can I create a union with formal parameter passed to a function in C++?

下面的函數計算32位浮點值的絕對值:

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

在函數中聲明的並集u包含變量x,該變量與在函數中作為參數傳遞的x不同。 有什么方法可以創建帶有函數參數-x的聯合嗎?

有什么原因使上面帶有注釋行的函數的執行時間比這個更長?

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

我正在嘗試找出盡可能少地對內存進行讀/寫操作以獲取浮點值Abs的最佳方法。

對於第一個問題,我不確定為什么您不能隨心所欲地完成任務。 編譯器將盡一切可能的優化。

在第二個示例代碼中。 您違反了嚴格的別名。 所以不一樣。

至於為什么它慢一些:

這是因為當今的CPU傾向於具有獨立的整數和浮點單元。 通過像這樣的類型調整,您可以將值從一個單位移動到另一個單位。 這有開銷。 (這通常是通過內存完成的,因此您需要額外的負載和存儲。)

在第二個片段中: a最初位於浮點單元(x87 FPU或SSE寄存器)中,需要移入通用寄存器以應用掩碼0x7FFFFFFF 然后需要將其移回。

在第一個代碼段中:編譯器可能足夠聰明,可以將a直接加載到整數單元中。 因此,您可以在第一階段繞過FPU。

(在向您展示程序集之前,我不確定100%。這在很大程度上還取決於參數是在寄存器中啟動還是在堆棧中啟動。輸出是否立即由其他浮點運算使用。)

看看在發布模式下編譯的代碼的反匯編,差異很明顯! 我刪除了內聯並使用了兩個虛擬函數,以使編譯器不會進行過多優化,並讓我們展示它們之間的差異。

這是第一個功能。

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  

這樣的微優化很難在長代碼中看到,但是如果在長串浮點運算中調用您的函數,則Fab將更好地工作,因為值已經存在於FPU堆棧或SSE寄存器中! 編譯器將更快,更好地優化abs。

您無法衡量在一段代碼中運行循環的優化性能,您必須查看編譯器如何在實際代碼中將所有這些混合在一起。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM