Fra*_*une 2 c c++ precision optimization intrinsics
当知道向量已经几乎是单位长度时,在性能关键代码中支付完整的向量归一化似乎是浪费的.
有没有人知道一种快速,实用的方法来使双精度3D矢量的长度接近1?我正在想象一个基于Newton-Raphson迭代或约1的有限泰勒展开的迭代方法.
这是一个真实的现实情况,这样的例程可能是有用的.该incoming载体是已几乎单位长度,但没有明确的正常化它仍然触发断言的路线.
使用SSE 2,SSE 4.2或AVX内在函数是可以的.
手头的问题归结为寻找(近似)倒数平方根.
SSE和AVX包括近似的倒数平方根机器指令,rsqrt特别适合于此.根据原始的AMD64架构程序员手册第1卷,倒数平方根变体的最大相对误差至多为1.5×2 -12,或小于0.0004.
如果使用GCC,可以使用__builtin_ia32_rsqrtss()SSE内置函数计算向量平方长度的倒数平方根,并将向量分量乘以结果,得到"几乎单位"向量.
请注意,SSE和AVX都提供加速平方长度计算的功能,以及每个组件的乘法.(但是,您需要将比例因子复制到相同大小的矢量.)
没有SSE/AVX,一般的问题是我们希望将矢量分量乘以f(S)≃sqrt(1/S)== 1/sqrt(S),其中S是内积(点积)矢量和它自身,即它的长度平方; 但是sqrt()被认为太慢了,已知S已接近1.
在我们认为"接近1"的范围内,任何函数f(S)的值都在1和sqrt(1/S)之间.我能想到的最简单的是形式为f(S)=(C + 1 - S)/ C的函数.对于S = 0.5 2到2 2(即对于长度在1/2和2之间的矢量),C是6.
如果我们没有任何硬件支持倒数平方根,我将尝试的第一个近似将是以下几行:
计算向量的平方长度S.
计算M = 0.125*(9 - S)
注意,任何常数对C 1和C 2 = 1 + 1/C 1都应该起作用,只有收敛的范围和速率变化.我为这个例子选择了C 1 = 1/8,因为它在IEEE-754浮点表示中是精确的,并且通常乘法比除法快得多.其他值(如上面提到的范围0.5到2的1/6)是不精确的,可能需要手工制作(在两个常数中以这种或那种方式调整最低有效单位).
通过乘以向量的每个分量中号.
如果这没有产生足够好的结果,我就不再担心了,而是使用(硬件)平方根.(在某些体系结构中,将平方长度转换为单精度以计算比例因子可以产生显着的加速.但不是在x86/AMD64上.)