Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast log2(float x) implementation C++

I need a Very-Fast implementation of log2(float x) function in C++.

I found a very interesting implementation (and extremely fast!)

#include <intrin.h>

inline unsigned long log2(int x)
{
    unsigned long y;
    _BitScanReverse(&y, x);
    return y;
}

But this function is good only for integer values in input.

Question: Is there any way to convert this function to double type input variable?

UPD:

I found this implementation:

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;
}

which is much faster than the previous example, but the output is unsigned type.

Is it possible to make this function return a double type?

Thanks in advance!

like image 448
Pomeron Avatar asked Feb 23 '12 11:02

Pomeron


2 Answers

If you just need the integer part of the logarithm, then you can extract that directly from the floating point number.

Portably:

#include <cmath>

int log2_fast(double d) {
    int result;
    std::frexp(d, &result);
    return result-1;
}

Possibly faster, but relying on unspecified and undefined behaviour:

int log2_evil(double d) {
    return ((reinterpret_cast<unsigned long long&>(d) >> 52) & 0x7ff) - 1023;
}
like image 74
Mike Seymour Avatar answered Oct 04 '22 21:10

Mike Seymour


MSVC + GCC compatible version that give XX.XXXXXXX +-0.0054545

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);
} 
like image 35
Louis Geoffroy Avatar answered Oct 04 '22 19:10

Louis Geoffroy