1

I'm looking for a way to find how often I can divide a constant x by two (and not get a remainder) without using loops, recursion or the logarithm. Since this is the same problem as finding the index of the least significant non-zero bit, I am hoping that there is some way to use bitwise operations to do this. Unfortunately I wasn't able to come up with it. Any ideas?

Background: I have a loop that doubles the counter on every iteration until it no longer divides the constant x. I want this loop to be unrolled, but the NVIDIA CUDA compiler isn't smart enough to figure out the number of iterations, so I want to rewrite the loop in such a way that the number of iterations becomes more obvious to the compiler:

for(i=1; CONST & i == 0; i *= 2)
     bla(i);

should become something like

#define ITERATIONS missing_expr_with_CONST
for(i=0; i < ITERATIONS; i++)
     fasel(i);
Nikratio
  • 2,338
  • 2
  • 29
  • 43
  • 3
    That would be the index of the MOST significant bit, and if you search SO, there are several questions about this. – EboMike Feb 17 '11 at 22:16
  • 2
    For example: http://stackoverflow.com/questions/2589096/find-most-significant-bit-left-most-that-is-set-in-a-bit-array – EboMike Feb 17 '11 at 22:18
  • Sorry, I described the problem the wrong way. I am truly looking for the least significant bit, see updated description. – Nikratio Feb 17 '11 at 22:27

5 Answers5

7

This can be directly solved using this code for 32 bit numbers (I take no credit).

unsigned int v;  // find the number of trailing zeros in 32-bit v 
int r;           // result goes here
static const int MultiplyDeBruijnBitPosition[32] = 
{
  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
  31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & -v) * 0x077CB531U)) >> 27];
CodeButcher
  • 564
  • 5
  • 16
3

You can also do this with pure arithmetic without a lookup table (the De Bruijn sequence approach requires a lookup table), but it's expensive. Here it goes:

m = (v&-v)-1;
i = ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12));

i is the index of the lowest-set bit in v. The formula is valid for values of v with up to 2000 or so zero bits, much larger than any integer type.

See here for an explanation:

Is there any way to compute the width of an integer type at compile-time?

Community
  • 1
  • 1
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • An impressive formula, but what this seems to do (also according to the linked question) is to count the total number of required bits, rather then the number of trailing zeros. Example: for 24 (11000b) this gives 5 rather than 3. – Nikratio Feb 19 '11 at 14:20
  • You missed the first line: `m = (v&-v)-1;`. This replaces 24 (in your example) with 7. – R.. GitHub STOP HELPING ICE Feb 19 '11 at 16:34
0

Do a right shift, then a left shift and check for equality with AND, increment a counter for each time this check is successful.

int powerOfTwo(int x) {
    int counter = 0;
    while(x > 0) {
        int y = x >> 1;
        y <<= 1;
        if(x ^ y) {
            counter++;
        } else {
            break;
        }
        x >>= 1;
    }
    return counter;
}

This uses a loop though... I can think of ways of eliminating the loop but it's basically "unfolding" the loop.

Argote
  • 2,155
  • 1
  • 15
  • 20
0

This can be easily done with a loop (this might not be 100% correct, so feel free to correct):

int leastSigBit(int num) {
  int result;
  for(result = 0; num & 1 != 1; ++result)
    num >>= 1;
  return result;
}

But I believe this is impossible to do without a loop as you're searching for a bit at an unknown position and thus must check all possible positions.

EDIT Revised based on updated description.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
0

If "pow" does not count as logarithm, here is a way to it for all numbers not just "2". The inverse functions that multiply instead of divide are also included for completeness.

GLSL code:

//://////////////////////////////////////////////////////////://
                                                     //://///://
//:IFDO: Move this somewhere more general IF you     //://///://
//:      ever find a need to call it from somewhere  //://///://
//:      else.                                       //://///://
int                                                  //://///://
ES2_AA2_Di2(                                         //://///://
    int B //:BASE:(Affected_Number)                  //://///://
,   int N //:NUMB:(Number_Of_Times_To_Divide_By_Two) //://///://
){                                                   //://///://

    //:programtic_equivalent_of_formula_below:---------------://
    //:                                                      ://
    //:    var b = B;                                        ://
    //:    for( var n = 0; n < N; n++ ){                     ://
    //:        b = b / 2;                                    ://
    //:    };;                                               ://
    //:    return( b /** R **/ );                            ://
    //:______________________________________________________://
  
    int R = int(  float(                  0  )   
        +         float(                  B  )    
        /           pow( float(2) , float(N) )  
    );;
  
    return( R );

    return( int(0) );
}//://////////////////////////////////////////| ES2_AA2_Di2 |://
//://////////////////////////////////////////////////////////://

JavaScript Code:

    //:B: Base                 //: MUL:A_NUMBER_OF_TIMES ://
    //:N: N number of times.   //: MUL:A_NUMBER_OF_TIMES ://
    const AA2_Mu2=( B, N )=>{ return(  B * (pow(2,N) ) ); };
    const AA2_Mu3=( B, N )=>{ return(  B * (pow(3,N) ) ); };
    const AA2_Mu4=( B, N )=>{ return(  B * (pow(4,N) ) ); };
    const AA2_Mu5=( B, N )=>{ return(  B * (pow(5,N) ) ); };
    
    //:B: Base                 //: DIV:A_NUMBER_OF_TIMES ://
    //:N: N number of times.   //: DIV:A_NUMBER_OF_TIMES ://
    const AA2_Di2=( B, N )=>{ return(  B / (pow(2,N) ) ); };
    const AA2_Di3=( B, N )=>{ return(  B / (pow(3,N) ) ); };
    const AA2_Di4=( B, N )=>{ return(  B / (pow(4,N) ) ); };
    const AA2_Di5=( B, N )=>{ return(  B / (pow(5,N) ) ); };

Transcribing to C is left as an exercise to the reader.

KANJICODER
  • 3,611
  • 30
  • 17