This is the fast inverse square root implementation from Quake III Arena:
这是Quake III Arena的快速反平方根实现:
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?
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 noticed that long int i
takes the dereferenced value at the address (cast to a long *
) of float y
. The code then performs operations on i
before storing the dereferenced value at the address (cast to a float *
) of i
into y
.
我注意到long int我在float y的地址(转换为long *)中取消引用的值。然后代码在i上执行操作,然后将解除引用的值存储在i的地址(转换为float *)中。
Would this break the strict aliasing rule since i
is not the same type as y
?
这是否会破坏严格的别名规则,因为我与y的类型不同?
I think that perhaps it doesn't since the value is dereferenced and copied; so the operations are performed on a copy rather than the original.
我想也许它不会,因为价值被解除引用和复制;所以操作是在副本而不是原件上执行的。
4 个解决方案
#1
6
Yes, this code is badly broken and invokes undefined behavior. In particular, notice these two lines:
是的,这段代码严重破坏并调用未定义的行为。特别注意这两行:
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
Since the object *(long *)&y
has type long
, the compiler is free to assume it cannot alias an object of type float
; thus, the compiler could reorder these two operations with respect to one another.
由于对象*(long *)和y的类型为long,编译器可以*地假设它不能为float类型的对象设置别名;因此,编译器可以相对于彼此重新排序这两个操作。
To fix it, a union should be used.
要修复它,应该使用联合。
#2
4
Yes, it breaks aliasing rules.
是的,它打破了别名规则。
In modern C, you can change i = * (long *) &y;
to:
在现代C中,你可以改变i = *(long *)&y;至:
i = (union { float f; long l; }) {y} .l;
and y = * (float *) &i;
to:
和y = *(浮动*)&i;至:
y = (union { long l; float f; }) {i} .f;
Provided you have guarantees that, in the C implementation being used, long
and float
have suitable sizes and representations, then the behavior is defined by the C standard: The bytes of the object of one type will be reinterpreted as the other type.
如果您保证在使用的C实现中,long和float具有合适的大小和表示,则行为由C标准定义:一种类型的对象的字节将被重新解释为另一种类型。
#3
3
Yes, it breaks aliasing rules.
是的,它打破了别名规则。
The cleanest fix for things like i = * ( long * ) &y;
would be this:
对于像i = *(long *)和y这样的东西最干净的修复;会是这样的:
memcpy(&i, &y, sizeof(i)); // assuming sizeof(i) == sizeof(y)
It avoids issues with alignment and aliasing. And with optimization enabled, the call to memcpy()
should normally be replaced with just a few instructions.
它避免了对齐和锯齿问题。在启用优化的情况下,对memcpy()的调用通常应该只用几条指令替换。
Just as any other method suggested, this approach does not fix any problems related to trap representations. On most platforms, however, there are no trap representations in integers and if you know your floating point format you can avoid floating point format trap representations, if there are any.
正如任何其他方法所建议的那样,此方法不会解决与陷阱表示相关的任何问题。但是,在大多数平台上,整数中没有陷阱表示,如果您知道浮点格式,则可以避免浮点格式陷阱表示(如果有)。
#4
1
i = * ( long * ) &y;
i = *(长*)&y;
This breaks aliasing rules and therefore invokes undefined behavior.
这会破坏别名规则,因此会调用未定义的行为。
You are accessing object y
with a type different than float
, or a signed / unsigned variant of char
.
您正在访问对象y,其类型不同于float,或者是有符号/无符号的char变体。
y = * ( float * ) &i;
y = *(float *)&i;
This statement above also breaks aliasing rules.
上面的这个陈述也打破了别名规则。
#1
6
Yes, this code is badly broken and invokes undefined behavior. In particular, notice these two lines:
是的,这段代码严重破坏并调用未定义的行为。特别注意这两行:
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
Since the object *(long *)&y
has type long
, the compiler is free to assume it cannot alias an object of type float
; thus, the compiler could reorder these two operations with respect to one another.
由于对象*(long *)和y的类型为long,编译器可以*地假设它不能为float类型的对象设置别名;因此,编译器可以相对于彼此重新排序这两个操作。
To fix it, a union should be used.
要修复它,应该使用联合。
#2
4
Yes, it breaks aliasing rules.
是的,它打破了别名规则。
In modern C, you can change i = * (long *) &y;
to:
在现代C中,你可以改变i = *(long *)&y;至:
i = (union { float f; long l; }) {y} .l;
and y = * (float *) &i;
to:
和y = *(浮动*)&i;至:
y = (union { long l; float f; }) {i} .f;
Provided you have guarantees that, in the C implementation being used, long
and float
have suitable sizes and representations, then the behavior is defined by the C standard: The bytes of the object of one type will be reinterpreted as the other type.
如果您保证在使用的C实现中,long和float具有合适的大小和表示,则行为由C标准定义:一种类型的对象的字节将被重新解释为另一种类型。
#3
3
Yes, it breaks aliasing rules.
是的,它打破了别名规则。
The cleanest fix for things like i = * ( long * ) &y;
would be this:
对于像i = *(long *)和y这样的东西最干净的修复;会是这样的:
memcpy(&i, &y, sizeof(i)); // assuming sizeof(i) == sizeof(y)
It avoids issues with alignment and aliasing. And with optimization enabled, the call to memcpy()
should normally be replaced with just a few instructions.
它避免了对齐和锯齿问题。在启用优化的情况下,对memcpy()的调用通常应该只用几条指令替换。
Just as any other method suggested, this approach does not fix any problems related to trap representations. On most platforms, however, there are no trap representations in integers and if you know your floating point format you can avoid floating point format trap representations, if there are any.
正如任何其他方法所建议的那样,此方法不会解决与陷阱表示相关的任何问题。但是,在大多数平台上,整数中没有陷阱表示,如果您知道浮点格式,则可以避免浮点格式陷阱表示(如果有)。
#4
1
i = * ( long * ) &y;
i = *(长*)&y;
This breaks aliasing rules and therefore invokes undefined behavior.
这会破坏别名规则,因此会调用未定义的行为。
You are accessing object y
with a type different than float
, or a signed / unsigned variant of char
.
您正在访问对象y,其类型不同于float,或者是有符号/无符号的char变体。
y = * ( float * ) &i;
y = *(float *)&i;
This statement above also breaks aliasing rules.
上面的这个陈述也打破了别名规则。