这个问题在这里已有答案:
我看到以下代码here。
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 heck?
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;
一般来说,我们使用*
和&
指针,但这里都使用变量。那么,它在这做什么?
该线正在采取float
,看着持有float
的记忆,重新解释那个记忆作为记忆持有long
,并得到那个long
。基本上,它将浮点数的位模式重新解释为整数的位模式,以便弄乱它的位。
不幸的是,该代码也是错误的。由于here描述的原因,不允许取消引用该转换指针。在C中,重新解释位模式的唯一方法是通过memcpy
。 (根据C变体和实现,通过联合也可以接受。)
首先,免责声明:这是技术上未定义的行为,因为它违反了strict aliasing rule,但大多数编译器将执行以下操作,我不知道首次编写时的标准情况。
当你看表达式时,有四个主要部分:(
y
是我们想要转换的浮点变量。很简单。&
是通常的地址运算符,所以&y
是指向y
的指针。(long *)
是指向long的指针,所以(long *) &y
是一个指向long的指针,指向内存中与y
相同的位置。那里没有真正的long
,只有float
,但如果float
和long
都是32位(就像代码所假设的那样),这将给你一个指向long
的指针,其具有与float
相同的位模式。*
取消引用指针。因此,完整的表达式,* ( long * ) &y;
,给你一个long
与y
相同的位模式。通常,具有与long
相同位模式的float
将是无用的,因为它们以完全不同的方式存储数字。然而,对long
进行位操作更容易,程序稍后将其转换回`float。
它表示y
(使其成为指针)的地址转换为long
指针,解除引用并分配给i
。