Pub*_*bby 6 c++ profile sse normalization approximation
我试图规范化4d向量.
我的第一个approch是使用SSE内在函数 - 这为我的向量算法提供了2倍的速度提升.这是基本代码:( v.v4是输入)(使用GCC)(所有内容都是内联的)
//find squares
v4sf s = __builtin_ia32_mulps(v.v4, v.v4);
//set t to square
v4sf t = s;
//add the 4 squares together
s = __builtin_ia32_shufps(s, s, 0x1B);
t = __builtin_ia32_addps(t, s);
s = __builtin_ia32_shufps(s, s, 0x4e);
t = __builtin_ia32_addps(t, s);
s = __builtin_ia32_shufps(s, s, 0x1B);
t = __builtin_ia32_addps(t, s);
//find 1/sqrt of t
t = __builtin_ia32_rsqrtps(t);
//multiply to get normal
return Vec4(__builtin_ia32_mulps(v.v4, t));
Run Code Online (Sandbox Code Playgroud)
我检查了反汇编,它看起来像我期待的.我没有看到任何大问题.
无论如何,然后我尝试使用近似值:(我从谷歌得到这个)
float x = (v.w*v.w) + (v.x*v.x) + (v.y*v.y) + (v.z*v.z);
float xhalf = 0.5f*x;
int i = *(int*)&x; // get bits for floating value
i = 0x5f3759df - (i>>1); // give initial guess y0
x = *(float*)&i; // convert bits back to float
x *= 1.5f - xhalf*x*x; // newton step, repeating this step
// increases accuracy
//x *= 1.5f - xhalf*x*x;
return Vec4(v.w*x, v.x*x, v.y*x, v.z*x);
Run Code Online (Sandbox Code Playgroud)
它运行速度略快于SSE版本!(大约快5-10%)它的结果也很准确 - 我会说找到长度时为0.001! 但是...... GCC给了我那种蹩脚的严格别名规则,因为它有类型的惩罚.
所以我修改它:
union {
float fa;
int ia;
};
fa = (v.w*v.w) + (v.x*v.x) + (v.y*v.y) + (v.z*v.z);
float faHalf = 0.5f*fa;
ia = 0x5f3759df - (ia>>1);
fa *= 1.5f - faHalf*fa*fa;
//fa *= 1.5f - faHalf*fa*fa;
return Vec4(v.w*fa, v.x*fa, v.y*fa, v.z*fa);
Run Code Online (Sandbox Code Playgroud)
而现在修改后的版本(没有警告)运行速度较慢 !! 它的运行速度几乎是SSE版本的60%(但结果相同)!为什么是这样?
所以这是问题:
我是个傻瓜 - 我意识到我在基准测试时运行了 SETI@Home。我猜它正在扼杀我的 SSE 表现。将其关闭并使其运行速度提高两倍。
我还在 AMD athlon 上测试了它并得到了相同的结果 - SSE 更快。
至少我修复了 shuf 错误!