理解快速平方根

时间:2018-01-29 02:25:22

标签: c pointers

我有一个问题不是关于算法,而是快速反平方根中的语法:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the...? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

我不懂行

i = * (long * ) &y;
y = * (float * ) &i;

我知道“& y”是y的内存地址,但我不知道“(long *)”是什么意思,或者开头的星号在做什么。

3 个答案:

答案 0 :(得分:1)

让我们声明一个整数: int main(){ char buffer[100]; int x; char y; read_line("x: ", buffer,sizeof(buffer)); sscanf(buffer, "%d", &x); while(1){ read_line("y: ", buffer,sizeof(buffer)); printf("%d\n", x); sscanf(buffer, "%s", &y); printf("%d\n", x); } return 0; }

现在让我们使用""地址获取foo的地址。运营商int foo;&返回指向-in的情况 - 整数:

&

上面的示例是存储解除引用int *bar = &foo; ,并将返回值转换为y或指向* long的指针。

答案 1 :(得分:1)

(long * )是一个演员,它基本上告诉编译器嘿,对待这个 浮点指针,好像它是一个长指针

开头的*是用于取消引用的一元运算符 指针。取消引用意味着通过指针访问内存:

int a = 10;
int *p = &a;

printf("%d\n", *p);

会打印10.它与执行p[0]相同。

所以

i = * (long * ) &y;

基本上是这样做的:将y视为指向long的指针并保存。{ yi指向的值。

这样做是将float值的内部位模式复制到i。 现在i将有一个基于该位模式的值。

y = * (float * ) &i;

这是相同的事情,但这次的价值为i

使用此代码确实通过float修改long位模式。该 代码甚至包含在评论 // evil floating point bit level hacking 中。 我不能告诉你它是如何工作的,因为我不知道快速反平方根算法。

答案 2 :(得分:1)

这是一个有趣的黑客,它基于32位整数和单精度浮点数的x86表示。如果没有测试,我认为它确实可以作为函数的一些近似值。

浮点数的*(long*)转换实际上采用浮点数(指数和小数位)表示的位,并按相同的顺序将它们分配给32位整数。基于地址的转换可确保在路上不会发生重新格式化,例如舍入,而int值将逐位等同于原始浮点值。即。

             s exponent fraction
 (float) y = 0 10000000 10010010000111111011011

 i = *(long*) y;

  ==>        long int value 
 (long)  i = 0 10000000 10010010000111111011011

然后对int值进行操作,包括右移'1',它影响int中的所有位,将所有指数和分数位向右移动并从常量中减去它。我不理解这部分背后的逻辑,但它导致了一个新的指数和分数位集,仍然以整数形式保存。

下一次转换为*(float*)将再次使浮点数与整数相同,但允许计算机将其用作浮点数并对其进行浮点运算。

因此,它仅适用于一组硬件平台,仅适用于32位算术。