The difference between (x^y) and !(!(x^y))

127 views Asked by At

I am a new computer science undergrad. For my assignment I need to implement isNotEqual(int x, int y) function in C by just using bitwise operators. This function will return false if x and y are equal, true otherwise. I have tried to just use x ^ y, but it couldn't pass all the test cases. My assumption was if only x and y are equal, it will return as a 0, and if they are not equal, it will return as a non-zero integer. In our first lessons, we learned that C returns non-zero values as true. To solve this problem I tried to use !(!(x ^ y)) and it worked. I can see the difference between my 2 solutions. For the second one, all the bits are converted to '1' but I don't understand why the simpler first solution doesn't work. Can someone explain why my first solution couldn't pass all the tests?

I tried:

int isNotEqual(int x, int y){
    return x^y;
}    

But the correct solution was:

int isNotEqual(int x, int y){
    return !(!(x^y));
}
4

There are 4 answers

0
Eric Postpischil On

You have not shown the text of the assignment. Likely one of these things is true:

  • The assignment specifies to return one if x and y are not equal and zero otherwise. In this case, you need to use return !! (x^y); or equivalent.
  • The assignment specifies to return non-zero if x and y are not equal and zero otherwise. In this case, return x^y; is sufficient and, if the test program complains, it is improperly written.
  • The assignment fails to specify what to return. In this case, the specification is deficient, and you should ask the instructor to complete it.
0
John Bollinger On

The difference between x^y and !(!(x^y)) is that when x and y are unequal, the former might take a wide range of nonzero values, but the latter will evaluate to exactly 1.

Any non-zero value is truthy in C, so your simpler implementation is plausible. It does not match the behavior of the != operator, however, which always evaluates to either 0 or 1, not any other value. Presumably, then, the latter behavior is what was expected. If the exercise was not clear about that then it was flawed, and you might have a case for a re-grade.

0
Jack Leow On

To answer your specific question: !(!(x)) will always evaluate to 0 or 1, regardless of the original value of x. Whereas x evaluates to x.

This is because the negation operator ! converts non-zero values to 0, and 0 to 1 always. As such if x above started out as:

  • 0, it'll be 0 -> 1 -> 0
  • Not 0 (1, -1, 123), it'll be x -> 0 -> 1

To make it concrete, the following:

#include <stdio.h>

int isNotEqual(int x, int y){
    return !(!(x^y));
}

int isNotEqual2(int x, int y){
    return x^y;
}

int main() {
    printf("isNotEqual(1, 1): %d\n", isNotEqual(1, 1));
    printf("isNotEqual2(1, 1): %d\n", isNotEqual2(1, 1));
    printf("isNotEqual(1, 123): %d\n", isNotEqual(1, 123));
    printf("isNotEqual2(1, 123): %d\n", isNotEqual2(1, 123));
}

Prints out:

isNotEqual(1, 1): 0
isNotEqual2(1, 1): 0
isNotEqual(1, 123): 1
isNotEqual2(1, 123): 122
0
Vlad from Moscow On

It seems it is the implementation of tests is incorrect or their requirements are very strict. I can suppose that they compare returned values of the function with exactly 0 and 1. So if two integers are not equal to each other then the first function can return any non-zero value depending on values of its arguments.

Instead of using the expression !(!(x^y)) that yileds either 1 or 0 you could just change the declaration of the function by changing its return type from int to _Bool as for example

_Bool isNotEqual(int x, int y){
    return x ^ y;
}  

From the C Standard (6.3.1.2 Boolean type)

1 When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1

Or you could include header <stdbool.h> and write

#include <stdbool.h>

bool isNotEqual(int x, int y){
    return x ^ y;
}  

Alternatively instead of using the expression !(!(x^y)) that is less readable you could also write

int isNotEqual(int x, int y){
    return ( x ^ y ) != 0;
}  

In this case again the function will return either 1 or 0.

As for the expression !(!(x^y)) then all what you should know is the following (The C Standard, 6.5.3.3 Unary arithmetic operators)

5 The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).

So if the sub-exoression x ^ y yields 0 then the subexpression !( x ^ y ) yields 1 and using one more the negation operator like !( !( x ^ y ) ) you will get again 0 if initially z ^ y yields 0.