In the C++ standard libraries I found only a floating point log method. Now I use log to find the level of an index in a binary tree ( floor(2log(index))
).
Code (C++):
int targetlevel = int(log(index)/log(2));
I am afraid that for some of the edge elements (the elements with value 2^n) log will return n-1.999999999999 instead of n.0. Is this fear correct? How can I modify my statement so that it always will return a correct answer?
assuming your x is > 0
Base-2 Integer Logarithm
Here is what I do for 64-bit unsigned integers. This calculates the floor of the base-2 logarithm, which is equivalent to the index of the most significant bit. This method is smokingly fast for large numbers because it uses an unrolled loop that executes always in log₂64 = 6 steps.
Essentially, what it does is subtracts away progressively smaller squares in the sequence { 0 ≤ k ≤ 5: 2^(2^k) } = { 2³², 2¹⁶, 2⁸, 2⁴, 2², 2¹ } = { 4294967296, 65536, 256, 16, 4, 2, 1 } and sums the exponents k of the subtracted values.
Note that this returns –1 if given the invalid input of 0 (which is what the initial
-(n == 0)
is checking for). If you never expect to invoke it withn == 0
, you could substituteint i = 0;
for the initializer and addassert(n != 0);
at entry to the function.Base-10 Integer Logarithm
Base-10 integer logarithms can be calculated using similarly — with the largest square to test being 10¹⁶ because log₁₀2⁶⁴ ≅ 19.2659...
I've never had any problem with floating-point accuracy on the formula you're using (and a quick check of numbers from 1 to 231 - 1 found no errors), but if you're worried, you can use this function instead, which returns the same results and is about 66% faster in my tests:
If you're using C++11 you can make this a constexpr function:
There are similar answers above. This answer
Functions:
Test Code:
If you are on a recent-ish x86 or x86-64 platform (and you probably are), use the
bsr
instruction which will return the position of the highest set bit in an unsigned integer. It turns out that this is exactly the same as log2(). Here is a short C or C++ function that invokesbsr
using inline ASM: