This post attempts to show you how Bitwise Operations work and why they work the way they do.
I will be using C# as our language and the Bitwise Operators that I will focus on will be:
It is important to understand that bitwise operations do their work on bit patterns at the bit level. So, if you were to run a binary AND (&) bitwise operation on the decimal value numbers (4 & 12), the (&) bitwise operator will operate on the corresponding bit patterns at their bit level – 0100 & 1100 (binary equivalent of 4 & 12). When bitwise operators are used on TRUE / FALSE values, the operation is still done at the bit level where TRUE = 1 and FALSE = 0. So, for example, the bitwise operation on (TRUE & FALSE) is converted to the binary equivalent of (1 & 0).
The point here is that bitwise operations are ALWAYS done at the bit level regardless of the original data types that the operation is done on – i.e. regardless if the expression is a set of integers or TRUE/FALSE values.
That being said, it is helpful to start off learning bitwise operations by, first, understanding what results occur when you run bitwise operations on TRUE / FALSE expressions. The three tables below show the results of running bitwise operations on all different possibilities of TRUE / FALSE values.
Bitwise & (AND)
For bool operands, the “&” bitwise operator computes the logical AND of its operands; that is, the result is true if and only if both its operands are true.
First Operand | Bitwise Operator | Second Operand | Result |
---|---|---|---|
TRUE | & | TRUE | TRUE |
TRUE | & | FALSE | FALSE |
FALSE | & | FALSE | FALSE |
FALSE | & | TRUE | FALSE |
C# Examples:
class Program { static void Main() { Console.WriteLine((true & true).ToString()); Console.WriteLine((true & false).ToString()); Console.WriteLine((false & false).ToString()); Console.WriteLine((false & true).ToString()); Console.ReadLine(); } } Output False False False |
Bitwise | Operator
For bool operands, | computes the logical OR of its operands; that is, the result is false if and only if both its operands are false.
First Operand | Bitwise Operator | Second Operand | Result |
---|---|---|---|
TRUE | | | TRUE | TRUE |
TRUE | | | FALSE | TRUE |
FALSE | | | FALSE | FALSE |
FALSE | | | TRUE | TRUE |
C# Example:
class Program { static void Main() { Console.WriteLine((true | true).ToString()); Console.WriteLine((true | false).ToString()); Console.WriteLine((false | false).ToString()); Console.WriteLine((false | true).ToString()); Console.ReadLine(); } } Output True False True |
Bitwise ^ Operator
For bool operands, ^ computes the logical exclusive-or of its operands; that is, the result is true if and only if exactly one of its operands is true.
First Operand | Bitwise Operator | Second Operand | Result |
---|---|---|---|
TRUE | ^ | TRUE | FALSE |
TRUE | ^ | FALSE | TRUE |
FALSE | ^ | FALSE | FALSE |
FALSE | ^ | TRUE | TRUE |
C# Example:
class Program { static void Main() { Console.WriteLine((true ^ true).ToString()); Console.WriteLine((true ^ false).ToString()); Console.WriteLine((false ^ false).ToString()); Console.WriteLine((false ^ true).ToString()); Console.ReadLine(); } } Output True False True |
The three tables above give you insight to how the &, |, and ^ bitwise operators work on TRUE / FALSE expressions. The rest of this post assumes that you understand the logic noted in the three tables above, so study (and memorize) the tables above to get a firm grasp on the bitwise logic before you continue to read further.
TRUE / FALSE Patterns
Bitwise Operations compare exactly two patterns. After the operation compares the two patterns, the operation returns a result. In this section we will examine the idea of what it means for bitwise operators to compare patterns.
Keep in mind that the following TRUE/FALSE comparison examples are JUST EXAMPLES! The intent of using the TRUE/FALSE comparison is to drill the bitwise logic into your head. The intent, at this point, is NOT to explain how the bitwise operators work in real C# code. Rather, the idea here is that if you fully understand how the TRUE/FALSE comparisons work, it will be a breeze for you to understand how the bitwise operators work in real code.
Consider this: We have two patterns that consist of a sequence of TRUE and FALSE values. (Remember: don’t think in terms of code right now. Think pure logic at this point)
Pattern 1 has the sequence: TRUE FALSE TRUE FALSE FALSE TRUE
Pattern 2 has the sequence: TRUE FALSE FALSE FALSE TRUE TRUE
When we say that we are going to compare the two patterns, we are implying that we are going to compare the patterns as if they were stacked on top of each-other and, then, compare the values in a columnar fashion.
To make sense of this, it’s best to view the patterns in a table. Notice, in the table below, how the two patterns are stacked in such a way that each of the values of Pattern 1 and Pattern 2 are in now columns. When we compare the values of Pattern 1 versus Pattern 2, we will be comparing the values within each Column.
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE |
Pattern 2 | TRUE | FALSE | FALSE | FALSE | TRUE | TRUE |
In Column 1 we will be comparing the values TRUE and TRUE. In Column 2 we will be comparing the values FALSE and FALSE. In Column 3 we will be comparing the values TRUE and FALSE and so on.
The way we compare the values within the columns is based on whichever Bitwise Operator we choose – i.e. & (AND), | (OR), or ^ (X0R).
Comparing TRUE/FALSE Patterns with & (AND)
Recall that the result of an & operator is true if and only if both its operands are true.
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE |
Pattern 2 | TRUE | FALSE | FALSE | FALSE | TRUE | TRUE |
& (AND) Result | TRUE | FALSE | FALSE | FALSE | FALSE | TRUE |
Note that a bitwise operation will always return a result. With that in mind, the bitwise operation result pattern of the & operation in the table above is:
TRUE FALSE FALSE FALSE FALSE TRUE
In other words, the bitwise & (AND) result of the pattern “TRUE FALSE TRUE FALSE FALSE TRUE” compared to the pattern “TRUE FALSE FALSE FALSE TRUE TRUE” is a new pattern that has the TRUE/FALSE sequence of “TRUE FALSE FALSE FALSE FALSE TRUE”.
Comparing TRUE/FALSE Patterns with | (OR)
Recall that the result of an | operator is false if and only if both its operands are false.
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE |
Pattern 2 | TRUE | FALSE | FALSE | FALSE | TRUE | TRUE |
| (OR) Result | TRUE | FALSE | TRUE | FALSE | TRUE | TRUE |
Remember that a bitwise operation will always return a result. With that in mind, the bitwise operation result pattern of the | operation in the table above is:
TRUE FALSE TRUE FALSE TRUE TRUE
In other words, the bitwise | (OR) result of the pattern “TRUE FALSE TRUE FALSE FALSE TRUE” compared to the pattern “TRUE FALSE FALSE FALSE TRUE TRUE” is a new pattern that has the TRUE/FALSE sequence of “TRUE FALSE TRUE FALSE TRUE TRUE”.
Comparing TRUE/FALSE Patterns with ^ (XOR)
Recall that the result of an ^ operator is true if and only if exactly one of its operands is true.
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE |
Pattern 2 | TRUE | FALSE | FALSE | FALSE | TRUE | TRUE |
^ (XOR) Result | FALSE | FALSE | TRUE | FALSE | TRUE | FALSE |
Remember that a bitwise operation will always return a result. With that in mind, the bitwise operation result pattern of the ^ operation in the table above is:
FALSE FALSE TRUE FALSE TRUE FALSE
In other words, the bitwise ^ (XOR) result of the pattern “TRUE FALSE TRUE FALSE FALSE TRUE” compared to the pattern “TRUE FALSE FALSE FALSE TRUE TRUE” is a new pattern that has the TRUE/FALSE sequence of “FALSE FALSE TRUE FALSE TRUE FALSE”.
Review What We’ve Done So Far
At this point in the game, all that we have really talked about is
- How bitwise operators evaluate TRUE/FALSE comparisons
- How to compare exactly two TRUE/FALSE patterns using either the & (AND), | (OR), or ^ (XOR) bitwise operators and create a new pattern based on those comparisons.
What we have NOT discussed is how bitwise operators work on numeric (integer) values within the C# language. This was done intentionally in order to stay focused on the fundamental logic of how bitwise operations work. However, if you have followed along and understood everything up to this point, you implicitly already know how bitwise operation works in C# integers.
Before we move on to working with bitwise operators on integer values (as opposed to boolean values), you must understand the basics of the binary number system. If you don’t understand the binary system, go read up on it first then come back here.
Binary Bitwise Patterns
Now that you fully understand the bitwise logic of TRUE/FALSE comparisons and you have a working knowledge of the binary number system, you are ready to move forward on understanding how bitwise operations work on integer values.
First things first – remember that
“A bitwise operation operates on one or more bit patterns or binary numerals at the level of their individual bits. [ref]“
Note the part of the definition that states, “…at the level of their individual bits.”. It is important to understand that the bitwise operations are always executed on the pattern of the individual bits of the value of the operands.
If that is true, how were we able to run bitwise operations on operands that have values of TRUE and/or FALSE? Good question!
In C#, TRUE and FALSE have their equivalent binary value; TRUE = binary 1 and FALSE = binary 0. You can easily prove this by running the following C# code:
class Program
{
static void Main()
{
int binaryTrue = Convert.ToInt16(true);
int binaryFalse = Convert.ToInt16(false);
Console.WriteLine(“Boolean ‘true’ converts to binary {0}”, binaryTrue);
Console.WriteLine(“Boolean ‘false’ converts to binary {0}”, binaryFalse);
Console.ReadLine();
}
}
Output:
Boolean 'true' converts to binary 1
Boolean 'false' converts to binary 0
Did you catch that? – a boolean TRUE value is equivalent to the binary value 1 and a boolean FALSE value is equivalent to 0 (zero). With this in mind, let’s revisit those three TRUE/FALSE tables that we talked about earlier where we compared Pattern 1 and Pattern 2:
Original TRUE/FALSE Pattern Comparison
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE |
Pattern 2 | TRUE | FALSE | FALSE | FALSE | TRUE | TRUE |
Convert TRUE/FALSE Pattern to Equivalent Binary Values
Now that we know that TRUE = binary 1 and FALSE = binary 0, let’s convert the original TRUE/FALSE table so that all the column values are the equivalent binary value. In other words, where we see a TRUE value, swap it out with a 1. Wherever we see a FALSE value, swap it out with a zero.
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | 1 | 0 | 1 | 0 | 0 | 1 |
Pattern 2 | 1 | 0 | 0 | 0 | 1 | 1 |
Keeping in mind that a value of one is the same as “TRUE” and a value of zero is the same as “FALSE”, we can use the same exact bitwise operational logic as we did in the TRUE/FALSE pattern tables to come up with the new binary pattern results.
Comparing Binary Patterns with & (AND)
Recall that the result of an & operator is true if and only if both its operands are true (i.e. are 1).
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | 1 | 0 | 1 | 0 | 0 | 1 |
Pattern 2 | 1 | 0 | 0 | 0 | 1 | 1 |
& (AND) Result | 1 | 0 | 0 | 0 | 0 | 1 |
Comparing Binary Patterns with | (OR)
Recall that the result of an | operator is false if and only if both its operands are false (i.e. are 0 (zero)).
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | 1 | 0 | 1 | 0 | 0 | 1 |
Pattern 2 | 1 | 0 | 0 | 0 | 1 | 1 |
|(OR) Result | 1 | 0 | 1 | 0 | 1 | 1 |
Comparing Binary Patterns with ^ (XOR)
Recall that the result of an ^ operator is true if and only if exactly one of its operands is true. (i.e. is 1).
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | |
Pattern 1 | 1 | 0 | 1 | 0 | 0 | 1 |
Pattern 2 | 1 | 0 | 0 | 0 | 1 | 1 |
^ (XOR) Result | 0 | 0 | 1 | 0 | 1 | 0 |
Boolean is Binary and Binary is Boolean in the Bitwise World!
If you were to compare the results of the TRUE/FALSE pattern tables with the results here in the Binary Pattern tables, you will find that the True/False Pattern Results are in perfect correlation (where TRUE=1; FALSE=0) with the Binary Pattern Results. – This is not a coincidence! The fact of the matter is, when thinking in the context of Bitwise Operations, you can think of binary values as nothing more than TRUE/FALSE patterns where 1 = TRUE and 0 = FALSE.
Review What We’ve Done So Far
At this point we have discussed the following:
- How bitwise operators evaluate TRUE/FALSE comparisons
- How to compare exactly two TRUE/FALSE patterns using either the & (AND), | (OR), or ^ (XOR) bitwise operators and create a new pattern based on those comparisons.
- We learned that boolean values have their equivalent binary values (where TRUE=1 and FALSE=0).
- Since boolean’s have their equivalent binary values, we learned that we can convert a TRUE/FALSE boolean pattern to its equivalent 1/0 binary pattern
Next up, we will update our Binary Pattern Tables such that the patterns have an actual integer value.
Update Binary Patterns Tables
Now it’s time to do some real Bitwise Operations. To do so, we will continue using our example Binary Pattern Tables, but we will make a minor modification to the tables such that we will replace “Column 1”, “Column 2”, and so on, with their equivalent binary number column. We do this so that we can visualize our tables as consisting of real binary numbers instead of just ones and zeros.
& (AND) Bitwise Operation Example
Recall that the result of an & operator is true if and only if both its operands are true (i.e. are 1).
32 | 16 | 8 | 4 | 2 | 1 | Expression | Result | |
Pattern 1 | 1 | 0 | 1 | 0 | 0 | 1 | 32+8+1 | 41 |
Pattern 2 | 1 | 0 | 0 | 0 | 1 | 1 | 32+2+1 | 35 |
& (AND) Result | 1 | 0 | 0 | 0 | 0 | 1 | 32+1 | 33 |
C# Code
class Program
{
static void Main()
{
int pattern1 = 41;
int pattern2 = 35;
int result = pattern1 & pattern2;
Console.WriteLine("pattern1 & pattern2 = {0}", result);
Console.ReadLine();
}
}
Output:
pattern1 & pattern2 = 33
| (OR) Bitwise Operation Example
Recall that the result of an | operator is false if and only if both its operands are false (i.e. are 0).
32 | 16 | 8 | 4 | 2 | 1 | Expression | Result | |
Pattern 1 | 1 | 0 | 1 | 0 | 0 | 1 | 32+8+1 | 41 |
Pattern 2 | 1 | 0 | 0 | 0 | 1 | 1 | 32+2+1 | 35 |
| (OR) Result | 1 | 0 | 1 | 0 | 1 | 1 | 32+8+2+1 | 43 |
C# Code
class Program
{
static void Main()
{
int pattern1 = 41;
int pattern2 = 35;
int result = pattern1 | pattern2;
Console.WriteLine("pattern1 | pattern2 = {0}", result);
Console.ReadLine();
}
}
Output:
pattern1 | pattern2 = 43
^ (XOR) Bitwise Operation Example
Recall that the result of an ^ operator is true if and only if exactly one of its operands is true (i.e. is 1).
32 | 16 | 8 | 4 | 2 | 1 | Expression | Result | |
Pattern 1 | 1 | 0 | 1 | 0 | 0 | 1 | 32+8+1 | 41 |
Pattern 2 | 1 | 0 | 0 | 0 | 1 | 1 | 32+2+1 | 35 |
^ (XOR) Result | 0 | 0 | 1 | 0 | 1 | 0 | 8+2 | 10 |
C# Code
class Program
{
static void Main()
{
int pattern1 = 41;
int pattern2 = 35;
int result = pattern1 ^ pattern2;
Console.WriteLine("pattern1 ^ pattern2 = {0}", result);
Console.ReadLine();
}
}
Output:
pattern1 ^ pattern2 = 10