快速浮点吸收功能

时间:2019-07-20 04:24:53

标签: c performance floating-point c99

在C99中的x86-64体系结构上获取标准32位浮点数绝对值的最快方法是什么?内置函数fabsffabs不够快。我目前的方法有点花哨:

unsigned int tmp = *((unsigned int *)&f) & 0x7fffffff;
float abs = *((float *)&tmp);

它可以工作,但是很难看。而且我不确定这是最佳选择吗?

请不要再告诉我有关类型标记指针的信息,因为这不是我要的。我知道代码可以使用联合用词表达,但这没关系,因为在所有编译器(在过去的十年中编写)上,它将发出完全相同的代码。

1 个答案:

答案 0 :(得分:1)

较少违反标准:

/* use type punning instead of pointer arithmatics, to require proper alignment */
static inline float float2absf(float f) {
  /* optimizer will optimize away the `if` statement and the library call */
  if (sizeof(float) == sizeof(uint32_t)) {
    union {
      float f;
      uint32_t i;
    } u;
    u.f = f;
    u.i &= 0x7fffffff;
    return u.f;
  }
  return fabsf(f);
}

恕我直言,使用库功能会更安全。这样可以提高代码的可移植性,尤其是在您可能会遇到非IEEE浮点表示形式或类型大小可能不同的平台上。

通常,为您的平台编译一次后,库函数应该提供最快的解决方案

话虽如此,除非经过优化,否则库调用既需要堆栈管理又需要代码跳转,对于简单的位更改功能,它可能导致两倍以上的操作以及缓存未命中。在许多情况下,通过使用编译器内置函数是可以避免的,这可以由编译器自动完成(它可以将库函数优化为内联指令)。

(理论上)您的位方法是正确的,可以优化与函数调用有关的操作,并可以改善代码局部性...尽管可以使用编译器内置函数和优化来实现。

另外,请注意,您的方法不符合标准,并且假设sizeof(int) == sizeof(float) ...我认为使用联合的类型修饰会有所改善。

此外,使用内联函数可以像使用宏一样工作,并使代码更具可读性。此外,如果类型大小不匹配,它可能会导致对库函数的后备。