2

下面的函数计算 32 位浮点值的绝对值:

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

函数中声明的 union u 包含变量 x,它与函数中作为参数传递的 x 不同。有没有办法创建一个带有函数参数的联合 - x?

上面带有未注释行的函数执行时间长于这个函数的任何原因?

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

我试图找出在尽可能少的读/写内存中获取浮点值的最佳方法。

4

2 回答 2

5

对于第一个问题,我不确定为什么你不能只是你想要的任务。编译器会做任何可以做的优化。

在您的第二个示例代码中。您违反了严格的别名。所以不一样。

至于为什么它更慢:

这是因为今天的 CPU 往往具有单独的整数和浮点单元。通过这样的类型双关语,您强制将值从一个单位移动到另一个单位。这有开销。(这通常是通过内存完成的,因此您有额外的加载和存储。)

在第二个片段中: a最初位于浮点单元(x87 FPU 或 SSE 寄存器)中,需要移动到通用寄存器中以应用掩码0x7FFFFFFF。然后需要将其移回。

在第一个片段中:编译器可能足够聪明,可以a直接加载到整数单元中。所以你在第一阶段绕过了 FPU。

(在您向我们展示程序集之前,我不能 100% 确定。它还很大程度上取决于参数是从寄存器开始还是从堆栈开始。以及输出是否立即被另一个浮点运算使用。)

于 2011-10-26T16:09:31.260 回答
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  

像这样的微优化很难在长代码中看到,但如果你的函数是在一长串浮点操作中调用的,那么 fab 会更好地工作,因为值已经在 FPU 堆栈或 SSE 寄存器中!编译器会更快更好地优化 abs 。

您无法衡量在一段代码中运行循环的优化性能,您必须了解编译器如何在真实代码中混合在一起。

于 2011-10-26T16:32:06.343 回答