2013-02-07 24 views
28

我阅读本文件:http://software.intel.com/en-us/articles/interactive-ray-tracing牛顿拉夫森与SSE2 - 有人可以给我解释一下这3个行

,我偶然发现了这三行代码:

的SIMD版本已经相当有点快,但我们可以做得更好。 英特尔为SSE2指令集添加了快速1/sqrt(x)函数。 唯一的缺点是它的精度有限。我们需要 精度,所以我们完善它用牛顿Rhapson:

__m128 nr = _mm_rsqrt_ps(x); 
__m128 muls = _mm_mul_ps(_mm_mul_ps(x, nr), nr); 
result = _mm_mul_ps(_mm_mul_ps(half, nr), _mm_sub_ps(three, muls)); 

此代码假定名为“半壁江山” (四次0.5F)和可变'一个__m128变量的存在三'(四次3.0f)。

我知道如何使用牛顿拉夫森计算函数的零点,我知道如何使用它来计算一个数的平方根,但我看不出这些代码如何执行它。

有人可以向我解释吗?

回答

34

鉴于牛顿迭代y_n+1=y_n(3-x(y_n)^2)/2,在源代码中看到它应该非常简单。

__m128 nr = _mm_rsqrt_ps(x);     // The initial approximation y_0 
__m128 muls = _mm_mul_ps(_mm_mul_ps(x, nr), nr); // muls = x*nr*nr == x(y_n)^2 
result = _mm_mul_ps(
       _mm_sub_ps(three, muls) // this is 3.0 - mul; 
    /*multiplied by */ __mm_mul_ps(half,nr) // y_0/2 or y_0 * 0.5 
); 

,也可以精确,这种算法是用于the inverse square root

请注意,这still doesn't give fully a fully accurate result。具有NR迭代的rsqrtps给出了近23位的精度,而对于sqrtps的24位具有对最后一位的正确舍入。

如果您想要truncate the result to integer,则精度有限是个问题。 (int)4.999994。另外,如果使用sqrt(x) ~= x * sqrt(x),请注意x == 0.0的情况,因为0 * +Inf = NaN

+0

当截断为整数时,你认为作为最后一步添加一个与结果指数相同的值,但只有在有效数中设置的最低位(或两个?)位是可行的吗?这当然是在最不重要的数字总是低于该位置的条件下。 – chili

+0

它取决于应用程序。关键是,当使用迭代方法'sqrt(n * n)== n'并不总是成立。这不能被任意“固定” - 因为'sqrt(n * n - epsilon)== n'可能会导致灾难。 –

3

要计算的a平方根倒数,牛顿法被应用到方程0=f(x)=a-x^(-2)与衍生物f'(x)=2*x^(-3)因此迭代步骤

N(x) = x - f(x)/f'(x) = x - (a*x^3-x)/2 
    = x/2 * (3 - a*x^2) 

此无划分方法具有 - 在对比的全局收敛Heron's method - 一个有限的收敛区域,所以你需要一个已经很好的逆平方根逼近来获得更好的近似。