0

I need to determine if a signed 32 bit number is a power of two. So far I know the first thing to do is check if its negative since negative numbers cannot be powers of 2. Then I need to see if the next numbers are valid etc... SO I was able to write it like this:

// Return 1 if x is a power of 2, and return 0 otherwise.
int func(int x)
{
     return ((x != 0) && ((x & (~x + 1)) == x));
}

But for my assignment I can only use 20 of these operators:

! ~ & ^ | + << >>

and NO equality statements or loops or casting or language constructs.

So I am trying to convert the equality parts and I know that !(a^b) is the same as a == b but I cant seem to figure it out completely. Any ideas on how to covert that to the allowed operators?

jameson
  • 9
  • 1
  • 2
  • 7
    It's going to be interesting to see if someone can find a way to answer this _without_ just giving you the answer. – Tim Post Sep 09 '11 at 13:42
  • 2
    A very useful trick to use in this situation is `!!x`. This normalises the number, so 0 becomes 0 and not-0 becomes 1. It's even efficient (compilers optimise for it). – David Given Sep 09 '11 at 13:43
  • 1
    I always have trouble with the !!x so if x = 2 and then !x = 1 and then !!x = 0. if x = 0, !x = 0 and !!x = 1? – jameson Sep 09 '11 at 13:46
  • @jameson: the opposite. `!` is a boolean negation. For every x<>0, !x is 0, and negating it again (!!x) gives 1. For x=0, !x = 1 and !!x = 0. – jweyrich Sep 09 '11 at 13:49
  • 7
    Can I open a new stackexchange site proposal for "Incompetent CS instructor X's do-everything-with-`!~&^|+<<>>` problems"? It's getting to the point where we have enough for a whole site... – R.. GitHub STOP HELPING ICE Sep 09 '11 at 13:50
  • @jameson: nope, you've got it backwards. Think about 0 meaning `false` and any other number meaning `true`. If x == 1, !x takes true and makes it false, so `!x` == 0. Since `!x` == 0, `!!x` == 1. – Daniel Sep 09 '11 at 13:51
  • @R.. I will 100% vote for (and answer the reams of questions on) said site. – Stephen Canon Sep 09 '11 at 13:51
  • @R..: I have to admit, I had one class where we had to do a lab full of those problems. I definitely think it's a great way to really understand bitwise operators. I really did not understand at all before that one lab. – Daniel Sep 09 '11 at 13:52
  • 2
    I think these problems would be good if the instructor also understood C, but the way he/she has stated them, they're not solvable in C and the desired "solutions" are full of undefined behavior (which could be fixed just by switching to unsigned arithmetic). I also think it's unfortunate that one student in the class found/knew Stack Overflow and told the whole class to come here to get their homework done for them... – R.. GitHub STOP HELPING ICE Sep 09 '11 at 13:54
  • 1
    Yeah, I'm getting a bit sick of this spate of "bitwise operator" questions too. Could conceivably vote to close as "too localized". – Oliver Charlesworth Sep 09 '11 at 14:05
  • At least it's not as bad as the daily `x++ + ++x` questions we were getting a few months back, and at least these are somewhat interesting. :-) – R.. GitHub STOP HELPING ICE Sep 09 '11 at 14:21
  • @R..: sadly we still get these, but [now they split the operands into function/method arguments](http://stackoverflow.com/questions/7356378/cout-vs-printf-order-of-execution). – jweyrich Sep 09 '11 at 14:25
  • @jweyrich: actually that one's a lot more interesting, and it's unclear to me still whether the C++ version has UB or not. I actually posted a followup question stripped to a minimal case and it's got conflicting answers on it. When I first saw your comment, I thought you were going to be giving me a hard time by linking to my own question. ;-) – R.. GitHub STOP HELPING ICE Sep 09 '11 at 14:34
  • @R..: haha, that would've been fun. Yeah, I personally consider sequence points to be one of the most disturbing things for one to understand. Hope not to be alone. – jweyrich Sep 09 '11 at 15:58

6 Answers6

5

Tim's comment ashamed me. Let me try to help you to find the answer by yourself.

What does it mean that x is power of 2 in terms of bit manipulation? It means that there is only one bit set to 1. How can we do such a trick, that will turn that bit to 0 and some other possibly to 1? So that & will give 0? In single expression? If you find out - you win.

Andrey
  • 59,039
  • 12
  • 119
  • 163
4

Try these ideas:

  • ~!!x+1 gives a mask: 0 if x==0 and -1 if x!=0.
  • (x&(~x+1))^x gives 0 if x has at most 1 bit set and nonzero otherwise, except when ~x is INT_MIN, in which case the result is undefined... You could perhaps split it into multiple parts with bitshifts to avoid this but then I think you'll exceed the operation limit.
  • You also want to check the sign bit, since negative values are not powers of two...

BTW, it sounds like your instructor is unaware that signed overflow is UB in C. He should be writing these problems for unsigned integers. Even if you want to treat the value semantically as if it were signed, you need unsigned arithmetic to do meaningful bitwise operations like this.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • How do you like them apples instructor? It always pains me that teachers are usually people with no industry experience. Their only experience is playing about. – Matt Joiner Sep 09 '11 at 13:51
  • 3
    I really don't get it. As someone who's been in academia (admittedly math rather than CS), I always expect rigor and attention to precise definitions in academic work. Yet again and again we see CS homework where the instructor obviously does not care about the precise definitions and specification of the language(s) they're working with... – R.. GitHub STOP HELPING ICE Sep 09 '11 at 13:58
  • The question implies that `1 << 31` should be false as its a negative number and not a power of 2. – Peter Lawrey Sep 09 '11 at 17:04
  • @Peter, no for a signed 32 bit number `1 << 31` is undefined behavior. – Jens Gustedt Sep 09 '11 at 18:12
  • @Jens: I think Peter was simply referring to `INT_MIN` in a less-than-rigorous manner. – R.. GitHub STOP HELPING ICE Sep 09 '11 at 18:38
  • @R.. I didn't realise it could have more than one result. Can you give me an example of how it could be be anything other than INT_MIN? – Peter Lawrey Sep 09 '11 at 18:47
  • @Peter: Overflow in signed arithmetic yields undefined behavior. 1 times 2 to the 31st power is larger than `INT_MAX`, so it overflows, and thus the behavior is undefined. – R.. GitHub STOP HELPING ICE Sep 09 '11 at 18:55
  • @R.. that makes a certain kind of sense, but does it ever happen in reality? – Peter Lawrey Sep 09 '11 at 19:06
  • 1
    @Peter: if you're asking about integer overflows, [it happens in real life](http://en.wikipedia.org/wiki/Ariane_5_Flight_501), and it's not infrequent. – jweyrich Sep 09 '11 at 19:17
  • @jweyrich, `1 << 31` is an example of an overflow. I wanted to know when its "undefined" behaviour would produce an unpredictable result. – Peter Lawrey Sep 09 '11 at 20:08
  • @Peter: As a constant, it's probably unlikely to. But consider `for (i=1; i>0; i<<=1) { ... }` A good compiler will compile this to an infinite loop. On a naive compiler, it will terminate when `i` overflows to negative. (I am assuming the loop does not otherwise modify `i`.) – R.. GitHub STOP HELPING ICE Sep 09 '11 at 20:37
  • @R.. It would appear that `gcc -O3` is not a good compiler ;) It stops when `i` is negative. ;) – Peter Lawrey Sep 09 '11 at 20:45
  • What if you change `i<<=1` to `i*=2`? I think gcc might have special-cased shifts because so many people abuse them and expect code with UB to "work"... – R.. GitHub STOP HELPING ICE Sep 09 '11 at 21:33
2

First, in your solution, it should be

return ((x > 0) && ((x & (~x + 1)) == x));

since negative numbers cannot be the power of 2. According to your requirement, we need to convert ">", "&&", "==" into permitted operators.

First think of ">", an integer>0 when its sign bit is 1 and it is not 0; so we consider

~(x >> 31) & (x & ~0)

this expression above will return a non zero number if x is non-positive. Notice that ~0 = -1, which is 0x11111111. We use x & ~0 to check if this integer is all 0 at each digit.

Secondly we consider "&&". AND is pretty straight forward -- we only need to get 0x01 & 0x01 to return 1. So here we need to add (!!) in front of our first answer to change it to 0x01 if it returns a nonzero number.

Finally, we consider "==". To test equity of A and B we only need to do

!(A ^ B)

So finally we have

return (!!(~(x >> 31) & (x & ~0))) & (!((x&(~x+1)) ^ x))

It seems that it's a homework problem. Please don't simply copy and paste. My answer is kind of awkward, it might be improved.

1
int ispower2(int x)
{

    int ispositive= ! ( (x>>31) ^ 0) & !!(x^0);         
    int temp= !((x & ~x+1) ^ x);
    return temp & ispositive;

}
Richard Erickson
  • 2,568
  • 8
  • 26
  • 39
1

Think about this... any power of 2 minus 1 is a string of 0s followed by a string of 1s. You can implement minus one by x + ~0. Think about where the string of 1s starts with relation to the single 1 that would be in a power of 2.

Daniel
  • 6,595
  • 9
  • 38
  • 70
0

It is interesting and efficient to use bitwise operators in C to solve some problems. In this question, we need to deal with two checks:

  1. the sign check. If negative, return 0; otherwise return 1;

    ! (x >> 31 & ox1) & !(!x)

    /* This op. extracts the sign bit in x. However, the >> in this case will be arithmetic. That means there will be all 1 before the last bit(LSB). For negative int, it is oxFFFFFFFF(-); otherwise, oxFFFFFFFE(+). The AND ox1 op. corrects the >> to ox1(-) or ox0(+). The Logical ! turns ox1(-) and ox0 (+) into 0 or 1,respectively. The !(!x) makes sure 0 is not power(2)*/

  2. the isPower(2) check. If yes, return 1; otherwise 0.

    !( x & (~x + ox1) ^ x )

    /* This op. does the isPower(2) check. The x & (~x + ox1) returns x, if and only if x is power(2). For example: x = ox2 and ~x + ox1 = oxFFFFFFFE. x & (~x + ox1) = ox2; if x = ox5 and ~x + ox1 = oxFFFFFFFB. x & (~x + ox1) = ox1. Therefore, ox2 ^ ox2 = 0; but ox5 ^ ox1 = ox4. The ! op turn 0 and others into 1 and 0, respectively.*/

The last AND op. between 1 and 2 checks will generate the result of isPower(2) function.

Z. Zhang
  • 209
  • 2
  • 4