views:

3295

answers:

8

I want to write a function that returns the nearest upper power of 2 number. For example if my input is 789, the output should be 1024. Is there any way of achieving this without using any loops but just using some bitwise operators?

+14  A: 

Check the Bit twidding hacks. You need to get the base 2 logarithm, then add 1 to that.

florin
+1  A: 

See here for possible solutions: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2Float

Stefan
+3  A: 

next=pow(2, ceil(log(x)/log(2));

This works by finding the number you'd have raise 2 by to get x (take the log of the number, and divide by the log of the desired base, see wikipedia for more). Then round that up with ceil to get the nearest whole number power.

This is a more general purpose (i.e. slower!) method than the bitwise methods linked elsewhere, but good to know the maths, eh?

Paul Dixon
Don't see much that's a bitwise operator here...
Jonathan Leffler
in EXCEL you can directly get the dual log by using =LOG(A1,2), so the whole formula would be =2^CEILING(LOG(L11,2),1)
MikeD
+2  A: 
unsigned long upper_power_of_two(unsigned long v)
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;
}
Eclipse
Would be nice if you have attributed it (unless you discovered it). It comes from the bit twiddling hacks page.
florin
Is that for a 32-bit number? Extension for 64-bit?
Jonathan Leffler
Jonathan, you need to do it for the upper half, and if that is zero, you do it for the lower half.
florin
@florin, if v is a 64-bit type, couldn't you just add a "c |= v >> 32" after the one for 16?
Evan Teran
http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
Judge Maygarden
@Evan: d'oh! of course (but I grew up with 32 bits...)
florin
Yup - it's from the bit-twiddling hacks as florin noted
Eclipse
A: 

If you need it for OpenGL related stuff:

/* Compute the nearest power of 2 number that is 
 * less than or equal to the value passed in. 
 */
static GLuint 
nearestPower( GLuint value )
{
    int i = 1;

    if (value == 0) return -1;      /* Error! */
    for (;;) {
         if (value == 1) return i;
         else if (value == 3) return i*4;
         value >>= 1; i *= 2;
    }
}
Paulo Lopes
'for' is a loop.
florin
florin: it is. and it is used as a loop here, isn't it?
DrJokepu
DrJokepu - I think florin meant to say here that the OP asked for a loop-less solution
Eli Bendersky
A: 

By way of clarification, do you need the nearest power of 2 (ie. 65 would give you 64, but 100 would give you 128) or the nearest above (ie. 65 would give you 128, and so would 100)?

Kim Reece
+2  A: 

The ultimate answer can be found at http://www.gamedev.net/community/forums/topic.asp?topic_id=229831

There are a few different ideas how to archive the desired result. Using loops, as in some of the examples here, is not at all necessary.

mafutrct
A: 

For IEEE floats you'd be able to do something like this.

int next_power_of_two(float a_F){
 int f = *(int*)&a_F;
 int b = f << 9 != 0; // If we're a power of two this is 0, otherwise this is 1

 f >>= 23; // remove factional part of floating point number
 f -= 127; // subtract 127 (the bias) from the exponent

 // adds one to the exponent if were not a power of two, 
 // then raises our new exponent to the power of two again.
 return (1 << (f + b)); 
}

If you need an integer solution and you're able to use inline assembly, BSR will give you the log2 of an integer on the x86. It counts how many right bits are set, which is exactly equal to the log2 of that number. Other processors have similar instructions (often), such as CLZ and depending on your compiler there might be an intrinsic available to do the work for you.

Jasper Bekkers
This is an interesting one eventhough not related to the question ( I want to roundoff only integers), will try out this one..
Naveen
Came up with it after reading the wikipedia article on floats. Besides that, I've used it to calculate square-roots in integer precision. Also nice, but even more unrelated.
Jasper Bekkers