【发布时间】:2021-01-13 22:55:03
【问题描述】:
我通过尝试优化某些事物(更少的变量等)来“玩”fast inverse sqrt 函数。这是最终代码:
float Q_rsqrt(float x) {
const float x2 = x * 0.5F;
uint_fast32_t i;
memcpy(&i, &x, sizeof(float));
i = 0x5f3759df - ( i >> 1 );
memcpy(&x, &i, sizeof(float));
return x * ( 1.5F - ( x2 * x * x ) );
}
首先,知道在我的架构上uint_fast32_t 用 64 位表示,float 用 32 位表示是很有用的。因此,在不同大小的变量类型上创建memcpy() 可能会令人惊讶。
编译代码后我遇到的问题是,每次使用相同的参数调用这个函数都会给出相同的返回值:有时这个是负的,有时是正的(但总是具有相同的绝对值)。
memcpy() 的用处是绕过以下代码的警告(取消引用类型双关指针会破坏严格的别名规则)(完全按照需要工作):
float Q_rsqrt_test(float x) {
const float xHalf = x * 0.5F;
const uint_fast32_t i = 0x5f3759df - ( (* ( uint_fast32_t * ) &x) >> 1 );
x = * ( float * ) &i;
return x * ( 1.5F - ( xHalf * x * x ) );
}
对于这段代码,我想说没有类型大小的问题,因为源(在上面的链接上可见)已经使用了double type,它在我的架构上以 64 位表示(而不是 @ 987654329@ 32 位)。
我真的不明白为什么我可以用第一个函数得到否定的答案......
感谢您的帮助。
【问题讨论】:
-
您只复制了 32 位,
i的其他 32 位未初始化。所以每次都可能不同。 -
先尝试初始化
i = 0;。 -
使用
uint32_t i将是另一种解决方案 -
啊,可能是这样...但是如果是这样,使用指针
*(uint_fast32_t *) &x的取消引用应该是“损坏的”,不是吗?我的意思是,这将在我们想要的浮点数之后再占用 32 位,因此很危险,因为我们不知道最后 32 位是什么?