Fast implementation of log2 (float x) C ++

I need a very fast implementation of the log2 (float x) function in C ++.

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

#include <intrin.h>

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

But this function is only good for integer input values.

Question: Is it possible to convert this function to an input variable double ?

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.

Is it possible for this function to return a double ?

Thanks in advance!

+5
source share
8 answers

If you only need the integer part of the logarithm, you can extract it from the floating point number.

Portable:

#include <cmath>

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

, , undefined:

int log2_evil(double d) {
    return ((reinterpret_cast<unsigned long long&>(d) >> 52) & 0x7ff) - 1023;
}
+5

: . Job .


() ( 5 × )

, . ; . - ( > ), :

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);
}
+4

MSVC + GCC, 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);
} 
+4

, :

  • .
  • std:: log
+2

++ 11 std:: log2 <cmath>.

+2

, IEEE, , IEEE, frexp() .

, , frexp, . 0,5 1,0, , 0.0 1.0 .

, , 5-10%, , . , , 2*.

#include <cmath>

double log2_fast(double d) {
    int exponent;
    double fraction = std::frexp(d, &exponent);
    return (result-1) + 2* (fraction - 0.5);
}

, :

#include <cmath>

int main()
{
   for(double x=0.001;x<1000;x+=0.1)
   {
      std::cout << x << " " << std::log2(x) << " " << log2_fast(x) << "\n";
   }
}
0
source

This function is not C ++; it is specific to MSVC ++. In addition, I doubt very much that such intrinsic properties exist. And if they did, the standard function would simply be configured to use it. So just call the standard library.

-1
source

No, but if you need only the whole part of the result and do not insist on portability, there is even faster. Because all you need is to extract the exponential part of the float!

-1
source