【问题标题】:Function with the same argument does not return the same value具有相同参数的函数不会返回相同的值
【发布时间】: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 位是什么?

标签: c uint64


【解决方案1】:

正如 Barmar 所说,将 i 初始化为 0 有效。我还认为最好避免取消引用其他大小的类型(例如*(uint64_t *) &x,其中 x 是浮点数)。使用 uint32_t 取消引用可能会更好,然后将结果正确地转换为 64 位变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-24
    • 2019-04-15
    • 1970-01-01
    • 2020-10-28
    • 2021-07-09
    相关资源
    最近更新 更多