下面的函数计算32位浮点值的绝对值:
__forceinline static float Abs(float x)
{
union {
float x;
int a;
} u;
//u.x = x;
u.a &= 0x7FFFFFFF;
return u.x;
}
在函数中声明的union你持有变量x,它与在函数中作为参数传递的x不同。有没有办法用函数的参数创建一个联合 - x?
任何原因上面的函数与未注释的行执行的时间比这个更长?
__forceinline float fastAbs(float a)
{
int b= *((int *)&a) & 0x7FFFFFFF;
return *((float *)(&b));
}
我正试图找出以尽可能少的读/写内存计数来获取浮点值Abs的最佳方法。
答案 0 :(得分:5)
答案 1 :(得分: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会更快,更好地由编译器优化。
你无法衡量在一段代码中运行循环的优化的性能,你必须看到编译器如何在实际代码中混合在一起。