如何理解 C/C++ 中的 指针别名(pointer alias)、restrict、const 的关系呢?
#include <stdio.h>
float Q_rsqrt( float number ) {
union { long l; float f; } i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i.f = y; // evil floating point bit level hacking
i.l = 0x5f3759df - ( i.l >> 1 ); // what the fuck?
y = i.f;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
int main() {
printf("%0.7f\n", Q_rsqrt(3.14));
printf("%0.7f\n", Q_rsqrt(1024.0));
printf("%0.7f\n", Q_rsqrt(10086.0));
printf("%0.7f\n", Q_rsqrt(2147483647.0));
printf("%0.14f\n", Q_rsqrt(3.14));
printf("%0.14f\n", Q_rsqrt(1024.0));
printf("%0.14f\n", Q_rsqrt(10086.0));
printf("%0.14f\n", Q_rsqrt(2147483647.0));
return 0;
}
代码实际上变简单了。
不过有趣的是,使用联合的版本给出的都是负值(虽然也是正确解,平方根有两个解),不知道符号位的处理和非联合版本有什么不同。
@无名啊,顺便一提,在安卓上long是64位,这就是符号位差异的来源
还有,memcpy
看起来是最佳选择,因为它没有任何多余的操作——我们想要的就是内存复制,所以我们就应该写内存复制。改成memcpy
后,代码比用联合与指针类型转换都简单。
#include <stdio.h>
#include <stdint.h> float Q_rsqrt( float number ) {
int32_t i = 0;
const float threehalfs = 1.5F;
float x2 = number * 0.5F;
float y = number;
memcpy(&i, &y, sizeof(y)); // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
memcpy(&y, &i, sizeof(y));
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
int main() {
printf("sizeof(long): %lu\n", sizeof(long));
printf("sizeof(int32_t): %lu\n", sizeof(int32_t));
printf("sizeof(float): %lu\n", sizeof(float));
printf("%0.7f\n", Q_rsqrt(3.14));
printf("%0.7f\n", Q_rsqrt(1024.0));
printf("%0.7f\n", Q_rsqrt(10086.0));
printf("%0.7f\n", Q_rsqrt(2147483647.0));
printf("%0.14f\n", Q_rsqrt(3.14));
printf("%0.14f\n", Q_rsqrt(1024.0));
printf("%0.14f\n", Q_rsqrt(10086.0));
printf("%0.14f\n", Q_rsqrt(2147483647.0));
return 0;
}
@老虎会游泳,cppreference 说,这是 UB: