Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if a number is non zero using bitwise operators in C

Check whether a number x is nonzero using the legal operators except !.

Examples: isNonZero(3) = 1, isNonZero(0) = 0

Legal ops: ~ & ^ | + << >>

  • Note : Only bitwise operators should be used. if, else, for, etc. cannot be used.
  • Edit1 : No. of operators should not exceed 10.
  • Edit2 : Consider size of int to be 4 bytes.

int isNonZero(int x) {
return ???;
}

Using ! this would be trivial , but how do we do it without using ! ?

like image 717
Eternal Learner Avatar asked Oct 12 '10 06:10

Eternal Learner


People also ask

How do you check if a number is negative using bitwise operators?

The expression ( n & (1 << (BITS -1 )) is to check MSB bit and gives 1 if the number is negative.

How do you know if a number is a bitwise operator?

The idea is to check whether the last bit of the number is set or not. If the last bit is set then the number is odd, otherwise even. As we know bitwise XOR Operation of the Number by 1 increment the value of the number by 1 if the number is even otherwise it decrements the value of the number by 1 if the value is odd.

What is Bitwise NOT operator in C?

Binary One's Complement or Bitwise NOT operator (~) in C: The C compiler recognizes the Bitwise NOT with ~ operator. It takes only one operand and performs the inversion of all digits of it. It is a unary operator. The output of this operator will invert all the existing bits of that operand.

How do you negate a number using bitwise operations?

The ~ (bitwise negation) operator yields the bitwise complement of the operand. In the binary representation of the result, every bit has the opposite value of the same bit in the binary representation of the operand.


5 Answers

The logarithmic version of the adamk function:

int isNotZero(unsigned int n){
  n |= n >> 16;
  n |= n >> 8;
  n |= n >> 4;
  n |= n >> 2;
  n |= n >> 1;
  return n & 1;
};

And the fastest one, but in assembly:

xor eax, eax
sub eax, n  // carry would be set if the number was not 0
xor eax, eax
adc eax, 0  // eax was 0, and if we had carry, it will became 1

Something similar to assembly version can be written in C, you just have to play with the sign bit and with some differences.

EDIT: here is the fastest version I can think of in C:

1) for negative numbers: if the sign bit is set, the number is not 0.

2) for positive: 0 - n will be negaive, and can be checked as in case 1. I don't see the - in the list of the legal operations, so we'll use ~n + 1 instead.

What we get:

int isNotZero(unsigned int n){ // unsigned is safer for bit operations
   return ((n | (~n + 1)) >> 31) & 1;
}
like image 148
ruslik Avatar answered Oct 04 '22 00:10

ruslik


int isNonZero(unsigned x) {
    return ~( ~x & ( x + ~0 ) ) >> 31;
}

Assuming int is 32 bits (/* EDIT: this part no longer applies as I changed the parameter type to unsigned */ and that signed shifts behave exactly like unsigned ones).

like image 21
usta Avatar answered Oct 04 '22 00:10

usta


Why make things complicated ?

int isNonZero(int x) {
    return x;
}

It works because the C convention is that every non zero value means true, as isNonZero return an int that's legal.

Some people argued, the isNonZero() function should return 1 for input 3 as showed in the example.

If you are using C++ it's still as easy as before:

int isNonZero(int x) {
    return (bool)x;
}

Now the function return 1 if you provide 3.

OK, it does not work with C that miss a proper boolean type.

Now, if you suppose ints are 32 bits and + is allowed:

int isNonZero(int x) {
    return ((x|(x+0x7FFFFFFF))>>31)&1;
}

On some architectures you may even avoid the final &1, just by casting x to unsigned (which has a null runtime cost), but that is Undefined Behavior, hence implementation dependant (depends if the target architecture uses signed or logical shift right).

int isNonZero(int x) {
    return ((unsigned)(x|(x+0x7FFFFFFF)))>>31;
}
like image 34
kriss Avatar answered Oct 04 '22 00:10

kriss


int is_32bit_zero( int x ) {
    return 1 ^ (unsigned) ( x + ~0 & ~x ) >> 31;
}
  1. Subtract 1. (~0 generates minus one on a two's complement machine. This is an assumption.)
  2. Select only flipped bit that flipped to one.
  3. Most significant bit only flips as a result of subtracting one if x is zero.
  4. Move most-significant bit to least-significant bit.

I count six operators. I could use 0xFFFFFFFF for five. The cast to unsigned doesn't count on a two's complement machine ;v) .

http://ideone.com/Omobw

like image 24
Potatoswatter Avatar answered Oct 04 '22 02:10

Potatoswatter


Bitwise OR all bits in the number:

int isByteNonZero(int x) {
    return ((x >> 7) & 1) |
           ((x >> 6) & 1) |
           ((x >> 5) & 1) |
           ((x >> 4) & 1) |
           ((x >> 3) & 1) |
           ((x >> 2) & 1) |
           ((x >> 1) & 1) |
           ((x >> 0) & 1);
}

int isNonZero(int x) {
  return isByteNonZero( x >> 24 & 0xff ) |
         isByteNonZero( x >> 16 & 0xff ) |
         isByteNonZero( x >> 8  & 0xff ) |
         isByteNonZero( x       & 0xff );
}
like image 30
adamk Avatar answered Oct 04 '22 01:10

adamk