views:

528

answers:

10

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 ! ?

+2  A: 

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 );
}
adamk
I'm not sure if creating a second function counts as a bitwise operator :)
JoshD
I'm not a C person and I'm wondering why `return x|(x` wouldn't work? Put that in your answer and I'll upvote.
Spencer Ruport
@Spencer Ruport: No, that won't work. That's a trivial identity; it will just return x. The result must be either 1 or 0.
JoshD
haylem
@JoshD: Why should the result be 1 or 0, in C every non zero values means true. The identity works perfectly :-) Try is in an if if you don't believe so.
kriss
@kriss: Yes, you're correct, but the question asks to return an integer with value either 0 or 1 as you can see from the function in the question. Otherwise you'd just return x and it would be a trivial problem.
JoshD
A: 

basically you need to or the bits. For instance, if you know your number is 8 bits wide:

int isNonZero(uint8_t x)
{
    int res = 0;
    res |= (x >> 0) & 1;
    res |= (x >> 1) & 1;
    res |= (x >> 2) & 1;
    res |= (x >> 3) & 1;
    res |= (x >> 4) & 1;
    res |= (x >> 5) & 1;
    res |= (x >> 6) & 1;
    res |= (x >> 7) & 1;

    return res;
}
Nathan Fellman
I think you have `<<` where you mean to have `>>`
benzado
You are using 24 bitwise operators here.
haylem
@haylem: When I wrote the answer, that wasn't one of the requirements
Nathan Fellman
@benzado: thanks! fixed it
Nathan Fellman
+15  A: 

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;
}
ruslik
Damn you I was going to post the same (except for the assembly part) :P +1 for THE solution
George B.
haylem
"sub" isn't a bitwise op; a C++ solution would be easier if we \'re allowed `-1`
MSalters
Why don't you just use neg? xor eax, eax; neg ecx; adc eax, 0;
wj32
@wj32 Yeah, this should work. I completely forgot which instructions affects CF.
ruslik
A: 
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

Potatoswatter
this doesn't work as requested. it returns -1 for x=0,
Matt Ellen
This will return 0 when x = 0x80000000
usta
also + and - are not allowed, if you allow them it's much more simple.
kriss
@kriss: `+` is explicitly allowed, see list.
MSalters
@Matt: No, that is why there is a cast to `unsigned`. See ideone link.
Potatoswatter
@usta: Yep, didn't think of that. Fortunately the fix is easy - use AND NOT instead of XOR.
Potatoswatter
@MSalters: Unary minus isn't though… eliminated it, although if I assume 32-bit two's complement I could just do `0xFFFFFFFF`.
Potatoswatter
@Potatoswatter: sorry, I didn't spot that before.
Matt Ellen
@Potatoswatter: Yep, that's essentially what I did. Now our solutions are very similar (use the same idea), yet not completely identical :)
usta
+5  A: 
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).

usta
I guess this assumes 2nd complement representation (x + ~0 == x-1)
Suma
On my Intel 32-bit Linux machine this function returns `0` or `-1`. If you subtract the answer from zero you would have a working function (on Intel 32-bit with gcc).
PP
@Suma: Yes, you are right
usta
@PP: That is why I wrote "Assuming ... signed shifts behave exactly like unsigned ones". This shows that on Intel 32-bit with gcc they don't behave the same, which is perfectly OK. In fact there are more problems with this solution when `x` is of signed type. I shall elaborate about that shortly...
usta
I changed the parameter type to unsigned not only because results of bitwise operations on signed types are implementation-defined when arguments have negative values, but also because adding and subtracting a non-zero constant cannot reliably be used either, as then there'll be at least one value of x with which `+` or `-` will result in overflow, and hence undefined behavior.
usta
+2  A: 

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;
}
kriss
because that's not the requirement. the requirement is to return 1 for non-zero
Matt Ellen
@Matt Ellen: let the OP write it would you ? When he wrote his question he stated `Example: isNonZero(3) = 1`, and example is not a requirement, never have been.
kriss
Ok, but your function doesn't fulfil the example either.
Matt Ellen
A: 

int isNonZero(int x)

{

if (  x & 0xffffffff)
    return 1;
else
    return 0;

}

Let assume Int is 4 byte.

It will return 1 if value is non zero

if value is zero then it will return 0.

Anand Kumar
`if` statements aren't allowed in the problem.
Nathan Fellman
A: 

My solution,though not quite related to your question

int isSign(int x)

{
//return 1 if positive,0 if zero,-1 if negative
return (x > 0) - ((x & 0x80000000)==0x80000000)
}
Tracy
Comparison operators are not allowed as per the question; Only bitwise operators.
Core Xii
A: 

Here's one that works regardless of the size of integers:

int isNonZero(int x) { return ~( (x & 0) == x ) + 2; }

Breakdown:

(x & 0) == x  // Returns 1 when x is 0, 0 when x <> 0

~( (x & 0) == x )  // Flips the bits, -2 when x is 0, -1 when x <> 0

~( (x & 0) == x ) + 2;  // OR by 2 to make results 0 or 1.
                        // (+ is bitwise OR or ADD, handy and underhanded)
GigaWatt
If you can use `==`, it's trivial. `return ~(x==0)`
aschepler
+1  A: 

Because I'm snotty:

return x;

works fine. I don't see any explicit requirements about the return value, and this happily yields the correct behavior if you stick the function call into a conditional expression.

quixoto
he shows that it has to return 1 or 0
pm100
Meh, sort of, but doesn't state explicitly as a requirement. It's a lame question, it's a poor interview question, and I'm leaving my answer here in protest.
quixoto
Really? a me too protest, that doesn't fulfil the example given. good work. Really helping the community.
Matt Ellen