tags:

views:

582

answers:

6

I have used the single ampersand (&) in C# to mean "check the second conditional statement even if the first is false".

But the following seems to be a different meaning of & altogether, can anyone explain how i & 1 works in the following example?

List<int> scores = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
var evenScores = scores.Where(i => i % 2 == 0);
var evenScores2 = scores.Where(i => (i & 1) == 0);
+3  A: 

Bitwise AND operator.

dove
+11  A: 

Here:

The unary & operator returns the address of its operand (requires unsafe context).

Binary & operators are predefined for the integral types and bool. For integral types, & computes the logical bitwise AND of its operands. For bool operands, & computes the logical AND of its operands; that is, the result is true if and only if both its operands are true.

The & operator evaluates both operators regardless of the first one's value.

Anton Gogolev
+6  A: 

For boolean types, what you mentioned is how it behaves.

For integer types, it's the bitwise "and" operator.

It can be overloaded for other types.

Basically, the expression (i & 1) == 0 checks to see whether the least significant bit of i is set, which only happens if the number is odd.

Mehrdad Afshari
+4  A: 

The ampersand represents a bitwise AND operation. A bitwise operator returns the result of a comparison between each corresponding bit in the two operands.

For example, if x is 0110 and y is 1010, then a bitwise AND of x and y (x & y) results in 0010.

Jeff Yates
+21  A: 

A single & is "Bitwise AND operator", just like dove said. I'm looking at second part of question: "why it works?"

Think in binary:

 000 = 0
 001 = 1
 010 = 2
 011 = 3
 100 = 4
 101 = 5
 110 = 6
 111 = 7
 and so on

Note all even numbers ends with 0; so if last bit bitwise check against 1 returns zero (meaning "doesn't match"), its a even number;

Rubens Farias
Steve314
@Steve: According to OP's question, they already know this behaviour exists as a way to not short-circuit boolean logic.
Jeff Yates
@Jeff - but he didn't know what the operator was, so didn't know why it worked for that. Just trying to relate existing knowledge to new, clarifying that the bool behaviour Edward knows falls out of bitwise behaviour you explained and the bool<->int casting behaviour.
Steve314
+2  A: 

Prior answers are true but don't address how & differs from &&, which I thought was your original question, so I'll take that.

As has been said, "&" is a bitwise AND. "&&" is a logical AND. & performs an AND operation on its operands bit by bit, and in general functions exactly like plus or times or any arithmetic operator. && is more complex. If compares each of its operands against zero. If the first operand is zero, it assumes the value FALSE and short-circuits the rest of the expression, i.e. it does not evaluate any remaining operands. If the first value is non-zero, it examines the second value. If this is zero it assumes the value of false, otherwise it assumes the value of true. In either case it continues to evaluate the expression.

That is, there are two crucial differences between & and &&:

  1. & operates bit by bit while && considers only zero and non-zero and always returns either 0 or 1. Thus 5 & 6 (binary 101 & 110) gives 4 (binary 100), while 5 && 6 gives 1 (true).

  2. && "short circuits". If the first value is zero, it does not evaluate the second value. & has no such rule. This is important in several ways. First, if the second value has any side effects, then with & those side effects always happen, while with && they do not. So "x & (y++)" will always increment y, while "x && (y++)" will only increment y if x is not zero. This gets more important -- and possibly more subtle -- if the second operand is a function call. Second, the first value may test something that determines that the second value is invalid. Like "x!=NULL && x->foo==3". With &, when x is null that could bomb with segment faults or the equivalent. And third, there may be important performance gains. Life, "x!='A' && readTonsOfStuffFromDatabaseAndCalculateTotal(x)". With &, the read would happen regardless, and perhaps be a total waste of time.

That's why we almost always use && for things that really are logical operations, and limit use of & to when we truly want a bit-wise operation. But there are times when you DON'T want the short-circuit to happen, and in that case & may be a good choice. But if you're using it to operate "logically", be very careful with operands that can have any values other than 0 or 1. 1 && 2 is true, but 1 & 2 is false.

Jay