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