快速log2(float x)实现C++

Pom*_*ron 7 c++ performance

我需要在C++中实现非常快速的log2(float x)函数.

我发现了一个非常有趣的实现(非常快!)

#include <intrin.h>

inline unsigned long log2(int x)
{
    unsigned long y;
    _BitScanReverse(&y, x);
    return y;
}
Run Code Online (Sandbox Code Playgroud)

但是此函数仅适用于输入中的整数值.

问题:有没有办法将此函数转换为double类型的输入变量?

UPD:

我找到了这个实现:

typedef unsigned long uint32;
typedef long int32;   
static inline int32 ilog2(float x)
{
    uint32 ix = (uint32&)x;
    uint32 exp = (ix >> 23) & 0xFF;
    int32 log2 = int32(exp) - 127;

    return log2;
}
Run Code Online (Sandbox Code Playgroud)

这比前一个示例快得多,但输出是无符号类型.

是否可以使此函数返回double类型?

提前致谢!

Mik*_*our 6

如果只需要对数的整数部分,则可以直接从浮点数中提取.

可移植:

#include <cmath>

int log2_fast(double d) {
    int result;
    std::frexp(d, &result);
    return result-1;
}
Run Code Online (Sandbox Code Playgroud)

可能更快,但依赖于未指定和未定义的行为:

int log2_evil(double d) {
    return ((reinterpret_cast<unsigned long long&>(d) >> 52) & 0x7ff) - 1023;
}
Run Code Online (Sandbox Code Playgroud)

  • 你的意思是它依赖于浮点数或双精度数的 IEEE 实现?当然库的实现者可能也想到了那个? (2认同)
  • @Pomeron你需要1.像这个答案一样提取以2为底的指数,2.通过用一些有理函数近似来计算“log2(1.mantissa)”(即近似值必须在区间“[1, 2”内有效) )`),以及 3. 将两个值相加。如果你需要精确度,大部分时间都会花在步骤 2 上,据我所知,这就是 `log2()` 的标准实现所做的。但是,如果您愿意牺牲一些精度来换取速度,则可以在区间“[1, 2)”上使用“log2()”的更快近似值。 (2认同)

Sim*_*ter 5

编辑:在下面的评论中查看 Job 的链接以获得更好的版本。


快速日志()函数 (5× faster approximately)

也许你感兴趣。代码在这里工作;虽然它不是无限精确。由于网页上的代码已损坏(> 已删除),我将在此处发布:

inline float fast_log2 (float val)
{
   int * const    exp_ptr = reinterpret_cast <int *> (&val);
   int            x = *exp_ptr;
   const int      log_2 = ((x >> 23) & 255) - 128;
   x &= ~(255 << 23);
   x += 127 << 23;
   *exp_ptr = x;

   val = ((-1.0f/3) * val + 2) * val - 2.0f/3;   // (1)

   return (val + log_2);
} 

inline float fast_log (const float &val)
{
   return (fast_log2 (val) * 0.69314718f);
}
Run Code Online (Sandbox Code Playgroud)

  • https://github.com/romeric/fastapprox 在相同精度下具有更快的函数,或者在精度更高的情况下具有几乎一样快的函数 (2认同)
  • 具体在此标头中:https://github.com/romeric/fastapprox/blob/master/fastapprox/src/fastlog.h (2认同)

小智 5

提供XX.XXXXXXX + -0.0054545的MSVC + GCC兼容版本

float mFast_Log2(float val) {
    union { float val; int32_t x; } u = { val };
    register float log_2 = (float)(((u.x >> 23) & 255) - 128);              
    u.x   &= ~(255 << 23);
    u.x   += 127 << 23;
    log_2 += ((-0.3358287811f) * u.val + 2.0f) * u.val  -0.65871759316667f; 
    return (log_2);
} 
Run Code Online (Sandbox Code Playgroud)

  • 使用[Remez'算法](http://en.wikipedia.org/wiki/Approximation_theory#Remez.27_algorithm)进行优化的公式,精度稍高(最大误差±0.00493976):`((-0.34484843f)* u.val + 2.02466578f)* u.val-0.67487759f` (2认同)
  • @netvope 非常感谢您的评论,让我开阔了视野,学习了近似理论! (2认同)

Pup*_*ppy -2

该函数不是 C++ 函数,而是 MSVC++ 特有的函数。另外,我非常怀疑是否存在这样的内在函数。如果他们这样做了,标准函数只需配置为使用它即可。所以只需调用标准提供的库即可。