13

~ & ^ | + << >> are the only operations I can use

Before I continue, this is a homework question, I've been stuck on this for a really long time.

My original approach: I thought that !x could be done with two's complement and doing something with it's additive inverse. I know that an xor is probably in here but I'm really at a loss how to approach this.

For the record: I also cannot use conditionals, loops, ==, etc, only the functions (bitwise) I mentioned above.

For example:

!0 = 1
!1 = 0
!anything besides 0 = 0
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
Jay
  • 131
  • 1
  • 1
  • 3
  • 2
    Do you really want them to evaluate directly to 1 and 0, or simply logical true and false? i.e. is `~0` acceptable as logical true? – Oliver Charlesworth Jan 21 '11 at 23:37
  • 1
    Note: `+` is not a bitwise operator. – Oliver Charlesworth Jan 21 '11 at 23:42
  • 2
    This kind of exercise is inherently meaningless because any *use* of the result requires a conditional that's essentially comparison against zero. My answer would be `if (var); else { /* your code here */ }` – R.. GitHub STOP HELPING ICE Jan 21 '11 at 23:43
  • 1
    @R.: The trick is that you don't need to use conditionals because C doesn't have `bool`. (E.g. instead of `return x != 0;` you can just say `return x;` assuming that he doesn't need `1` returned... that's what I'm trying to figure out.) – user541686 Jan 21 '11 at 23:44
  • 1
    @Mehrdad: C99 does have `bool`, but AFAIK you have to include `stdbool.h` to get it unless you're happy saying `_Bool`. – mu is too short Jan 22 '11 at 03:24
  • @mu is too short: Haha... *every* time I say "C doesn't have feature X" someone immediately replies that C99 has it. :) I stand corrected, although I never refer to C99 unless I mention it explicitly. – user541686 Jan 22 '11 at 03:28
  • @Oli Charlesworth - Unary + could be considered bitwise. – Chris Lutz Feb 06 '11 at 10:24

6 Answers6

10

Assuming a 32 bit unsigned int:

(((x>>1) | (x&1)) + ~0U) >> 31

should do the trick

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
8

Assuming x is signed, need to return 0 for any number not zero, and 1 for zero.

A right shift on a signed integer usually is an arithmetical shift in most implementations (e.g. the sign bit is copied over). Therefore right shift x by 31 and its negation by 31. One of those two will be a negative number and so right shifted by 31 will be 0xFFFFFFFF (of course if x = 0 then the right shift will produce 0x0 which is what you want). You don't know if x or its negation is the negative number so just 'or' them together and you will get what you want. Next add 1 and your good.

implementation:

int bang(int x) {
    return ((x >> 31) | ((~x + 1) >> 31)) + 1;
}
phuclv
  • 37,963
  • 15
  • 156
  • 475
lock14
  • 81
  • 1
  • 2
  • I think you should negate instead of adding one. Namely, `~((x >> 31) | ((~x + 1) >> 31))`. – user1857492 Sep 17 '17 at 09:32
  • Actually, no. Adding 1 is correct. I forgot that `>>` shifts are arithmetic in C, not logical. Thus, `>> 31`-ing `10...00` will yield `11...11`, not `00...01`. – user1857492 Sep 17 '17 at 17:00
1

The following code copies any 1 bit to all positions. This maps all non-zeroes to 0xFFFFFFFF == -1, while leaving 0 at 0. Then it adds 1, mapping -1 to 0 and 0 to 1.

x = x | x << 1  | x >> 1
x = x | x << 2  | x >> 2
x = x | x << 4  | x >> 4
x = x | x << 8  | x >> 8
x = x | x << 16 | x >> 16

x = x + 1
wnoise
  • 9,764
  • 37
  • 47
1

For 32 bit signed integer x

// Set the bottom bit if any bit set.
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;

x ^= 1;   // Toggle the bottom bit - now 0 if any bit set.
x &= 1;   // Clear the unwanted bits to leave 0 or 1.
Dipstick
  • 9,854
  • 2
  • 30
  • 30
0

Assuming e.g. an 8-bit unsigned type:

~(((x >> 0) & 1)
| ((x >> 1) & 1) 
| ((x >> 2) & 1)
...
| ((x >> 7) & 1)) & 1
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
-3

You can just do ~x & 1 because it yields 1 for 0 and 0 for everything else

Noah
  • 1