5

Possible Duplicate:
Finding consecutive bit string of 1 or 0

Is it possible to count, from left, consecutive 1's in an integer? So: total number of consecutive set bits starting from the top bit.

Using only:

! ~ & ^ | + << >>

-1= 0xFFFFFFFF would return 32

0xFFF0F0F0 would return 12 (FFF = 111111111111)

No loops, unfortunately.

Can assume the machine:

  1. Uses 2s complement, 32-bit representations of integers.

  2. Performs right shifts arithmetically.

  3. Has unpredictable behavior when shifting an integer by more than the word size.

I'm forbidden to:

  1. Use any control constructs such as if, do, while, for, switch, etc.

  2. Define or use any macros.

  3. Define any additional functions in this file.

  4. Call any functions.

  5. Use any other operations, such as &&, ||, -, or ?:

  6. Use any form of casting.

  7. Use any data type other than int. This implies that you cannot use arrays, structs, or unions.

I've looked at Finding consecutive bit string of 1 or 0 It's using loops, which I can't use. I don't even know where to start.

(Yes, this is an assignment, but I'm simply asking those of you skilled enough for help. I've done pretty much all of those I need to do, but this one just won't work.)

(For those downvoting simply because it's for school: FAQ: 1 a specific programming problem, check 2 However, if your motivation is “I would like others to explain ______ to me”, then you are probably OK.)

Community
  • 1
  • 1
Mappan
  • 2,537
  • 2
  • 22
  • 27
  • How about walking the bits from left to right (or R -> L) if the bit at the current place is '1' do some action, if it is '0' do some other action? – wildplasser Sep 26 '12 at 15:47
  • For a second I was tricked by this: "For those downvoting simply because it's for school: FAQ" =)))) – Razvan Sep 26 '12 at 15:47
  • This seems sort of trivial, so unless you give us a clue where you're stuck, it's hard to think of a constructive answer. I could just write a couple of sample solutions, of course. – Useless Sep 26 '12 at 15:48
  • It is OK to ask assignment questions as long as you include what you've tried and explain which portion you need help with. See [How to ask and answer homework questions](http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions/10812#10812) – Shawn Chin Sep 26 '12 at 15:49
  • yes, because it is asking for consecutive 1's not total. – Scott Sep 26 '12 at 15:50
  • Would it have to be portable, or can we assume two's complement? – Daniel Fischer Sep 26 '12 at 15:53
  • two's complement can be assumed. – Mappan Sep 26 '12 at 15:58
  • Why do you need to count from the left ? The largest no of consecutive 1s will be the same whichever direction you count from, no ? – Paul R Sep 26 '12 at 16:00
  • ah, is it the _total number of consecutive set bits starting from the top bit_? Not the longest run of set bits? – Useless Sep 26 '12 at 16:03
  • Yes Useless, I'll word it better. – Mappan Sep 26 '12 at 16:05
  • OK - so you just need to find the most significant 0 bit ? – Paul R Sep 26 '12 at 16:05
  • Yes, that makes sense, and then count the 1'n "above" that. That actually clarifies things. My heads been going in circles these last few days. – Mappan Sep 26 '12 at 16:09
  • 1
    FWIW, this is a _terrible_ assignment IMO. – Useless Sep 26 '12 at 16:54
  • @Zanii Did I get you correctly that constants greater than 0xFF are forbidden? – Serge Sep 27 '12 at 00:58

5 Answers5

2

You can do it like this:

int result = clz(~x);

i.e. invert all the bits and then count leading zeroes.

clz returns the number of leading zero bits (also commonly known as ffs or nlz) - see here for implementation details: http://en.wikipedia.org/wiki/Find_first_set#Algorithms

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • Surely this is just the equivalent of counting the number of leading ones? Which will not give the correct result if the 'consecutive ones' appear anywhere other than at the start of the int. – Lee Netherton Sep 26 '12 at 16:21
  • @Lee: the question was somewhat ambiguous as originally worded but it seems that the OP does actually want the number of leading 1s - see the later comments under the question. – Paul R Sep 26 '12 at 16:50
  • 1
    Ok, I read it as being the longest run of bits, but I see he has reworded it now. – Lee Netherton Sep 26 '12 at 16:58
2

Here you are. The function argument may be signed or unsigned. The alg is independent on signedness.

int leftmost_ones(int x)
{
    x = ~x;
    x = x | x >> 1 | x >> 2 | x >> 3 | x >> 4 | x >> 5 | x >> 6 | x >> 7 | 
        x >> 8 | x >> 9 | x >> 10 | x >> 11 | x >> 12 | x >> 13 | x >> 14 | 
        x >> 15 | x >> 16 | x >> 17 | x >> 18 | x >> 19 | x >> 20 | x >> 21 | 
        x >> 22 | x >> 23 | x >> 24 | x >> 25 | x >> 26 | x >> 27 | x >> 28 | 
        x >> 29 | x >> 30 | x >> 31;
    x = ~x;
    return (x & 1) + (x >> 1 & 1) + (x >> 2 & 1) + (x >> 3 & 1) + (x >> 4 & 1) + 
        (x >> 5 & 1) + (x >> 6 & 1) + (x >> 7 & 1) + (x >> 8 & 1) + (x >> 9 & 1) + 
        (x >> 10 & 1) + (x >> 11 & 1) + (x >> 12 & 1) + (x >> 13 & 1) + (x >> 14 & 1) +
        (x >> 15 & 1) + (x >> 16 & 1) + (x >> 17 & 1) + (x >> 18 & 1) + (x >> 19 & 1) +
        (x >> 20 & 1) + (x >> 21 & 1) + (x >> 22 & 1) + (x >> 23 & 1) + (x >> 24 & 1) +
        (x >> 25 & 1) + (x >> 26 & 1) + (x >> 27 & 1) + (x >> 28 & 1) + (x >> 29 & 1) +
        (x >> 30 & 1) + (x >> 31 & 1);
}

A version with some optimization:

int leftmost_ones(int x)
{
    x = ~x;
    x |= x >> 16;
    x |= x >> 8;
    x |= x >> 4;
    x |= x >> 2;
    x |= x >> 1;
    x = ~x;

    return (x & 1) + (x >> 1 & 1) + (x >> 2 & 1) + (x >> 3 & 1) + (x >> 4 & 1) + 
        (x >> 5 & 1) + (x >> 6 & 1) + (x >> 7 & 1) + (x >> 8 & 1) + (x >> 9 & 1) + 
        (x >> 10 & 1) + (x >> 11 & 1) + (x >> 12 & 1) + (x >> 13 & 1) + (x >> 14 & 1) +
        (x >> 15 & 1) + (x >> 16 & 1) + (x >> 17 & 1) + (x >> 18 & 1) + (x >> 19 & 1) +
        (x >> 20 & 1) + (x >> 21 & 1) + (x >> 22 & 1) + (x >> 23 & 1) + (x >> 24 & 1) +
        (x >> 25 & 1) + (x >> 26 & 1) + (x >> 27 & 1) + (x >> 28 & 1) + (x >> 29 & 1) +
        (x >> 30 & 1) + (x >> 31 & 1);
}
Serge
  • 6,088
  • 17
  • 27
  • Thank you very much. I'm going to study this and try to use as few operators as possible. Thank you again. – Mappan Sep 26 '12 at 16:52
  • You are welcome. The tricky part is to leave only ones that we like to count. The expression in return statement is just a sum of all bit values in the 'cleaned up' argument – Serge Sep 26 '12 at 16:57
  • Hmm, downvoter, could you please explain your reasons to give -1? The solution satisfies all restrictions in the question and produces correct result. It's hard to read, or it's hard to understand the logic? – Serge Sep 26 '12 at 17:52
  • I know this is possible with fewer ops. But I've got NO idea how. – Mappan Sep 26 '12 at 21:52
  • You asked for a solution, but you did not ask for an optimal solution) – Serge Sep 26 '12 at 22:09
  • I know. Just sort of asking/thinking "outloud". – Mappan Sep 26 '12 at 22:41
  • )) You made me thinking on your assignment again... I will share if I find more elegant solution – Serge Sep 26 '12 at 22:42
  • You managed to take 50 ops of it. Well done. Better then what I could do. Thank you once again! – Mappan Sep 27 '12 at 00:39
  • You can use http://stackoverflow.com/questions/109023/best-algorithm-to-count-the-number-of-set-bits-in-a-32-bit-integer for the return statement. – Ivo Sep 27 '12 at 08:06
  • @ivo unfortunately no, as Zanii says that he can't use constants greater than 0xFF if I got him correcty – Serge Sep 27 '12 at 08:15
  • @Serge fair enough, but you can still do the same thing four times to get the bits for each byte :) – Ivo Sep 27 '12 at 09:21
1

Can you use a loop?

int mask = 0x80000000;
int count = 0;
while (number & mask) {
    count += 1;
    mask >>= 1;
}
001
  • 13,291
  • 5
  • 35
  • 66
1

I think it's doable, by basically unrolling the typical loop and being generally annoying.

How about this: an expression that is 1 if and only if the answer is 1? I offer:

const int ok1 = !((number & 0xc0000000) - 0x800000000);

The ! and subtraction are to work around that someone broke the == key on our keyboard, of course.

And then, an expression that is 1 if and only if the anwer is 2:

const int ok2 = !((number & 0xe0000000) - 0xc0000000);

If you continue to form these, the final answer is their sum:

const int answer = ok1 + ok2 + ... + ok32;

By the way, I can't seem to remember being given these weirdly restricted assignments when I was in school, I guess times have changed. :)

unwind
  • 391,730
  • 64
  • 469
  • 606
  • I can't use "-" or numbers bigger then 0xFF so I'll have to say: !((number & (1<<31)) + ~(1<<31));, but I will try this. – Mappan Sep 26 '12 at 16:43
  • @Zanii D'oh, forgot about the subtraction. Didn't know about the literals. Giving up on this, random restrictions on programming is ... not very helpful, it's like walking in a minefield. :) – unwind Sep 26 '12 at 16:45
  • Yeah, it's a good way to get you to understand bitwise operators, but it's also a good way in making simple things as hard as can be. – Mappan Sep 26 '12 at 16:54
0
int count_consecutive_bits(unsigned int x) {
    int res = 0;
    while (x & 0x80000000) { ++res; x <<= 1; }
    return res;
}
Mark
  • 6,033
  • 1
  • 19
  • 14