Modern programming languages are designed to make code readable for humans, while the compilers handling the heavy lifting to convert it into machine code. However, most programming languages still provide ways to manipulate data as sequences of bits, as opposed to common types such as numbers and strings. Bitwise Operators are the way to do so. Here’s a detailed explanation of each bitwise operator:
1. OR (|)
This operator returns 1 if at least one of the bits in the corresponding positions of the operands is 1. Otherwise, it returns 0. For example:
1101 (13 in binary)
1010 (10 in binary)
-------
1111 (15 in binary)
2. AND (&)
The AND operator returns 1 only when both bits in the corresponding positions of the operands are 1. Otherwise, it returns 0. For example:
1101 (13 in binary)
1010 (10 in binary)
-------
1000 (8 in binary)
3. XOR (^)
XOR, or exclusive OR, returns 1 when the bits in corresponding positions are different, and 0 when they are the same. For example:
1101 (13 in binary)
1010 (10 in binary)
-------
0111 (15 in binary)
4. NOT (!)
The NOT operator inverts the value of a bit. It changes 0 to 1 and 1 to 0. For example:
1101 (13 in binary)
-------
0010 (2 in binary)
5. Left Shift (<<)
The left shift operator is used to shift the bits of a binary number to the left by a specified number of positions. Each shift to the left effectively multiplies the number by 2, and it introduces zeros on the right to fill the vacated positions. This process continues until the number of shifts reaches the boundary of the available bits. For example:
001010 << 2
-------
101000
6. Right Shift (>>)
The right shift operator is used to shift the bits of a binary number to the right by a specified number of positions. Each shift to the right divides the number by 2, and it adds zeros on the left side of the result. For example:
001010 >> 2
-------
001000
Basics of using Bitwise Operators
Finding if a Specific Bit is Set or Unset
To check if the nth
bit in a given number is set or unset, we can follow a straightforward procedure. First, we take left shift of the number 1
by n
positions. This operation gives us a number where all bits are unset except for the nth
bit, which is set. Let’s call it the mask. Then, we perform a bitwise AND operation between this mask and our original number. If the nth
bit is set in our original number, the result of the bitwise AND operation will be 1
. Consequently, we can confidently conclude that the bit is set. If the result is 0
, we can safely conclude that the bit is unset. See the following snippet of code in python:
bitPosition = 5
number = 34
# Create a mask by left-shifting 1 by bitPosition positions
mask = 1 << bitPosition
if number & mask != 0:
print("The bit is Set")
else:
print("The bit is Unset")
Setting a Specific Bit
To set the nth
bit in a given number, we will follow the same approach as above. But instead of using the bitwise AND operation, here we will make use of bitwise OR. We will again create a mask by performing a left shift on the number 1
by n
positions. This mask will have only the nth
bit set to 1
, with all other bits set to 0
. Then we perform a bitwise OR operation between the original number and the mask. This operation will set the nth
bit in the original number to 1
while leaving all other bits unchanged. Here is the python code:
bitPosition = 3
number = 10
# Create a mask by left-shifting 1 by bitPosition positions
mask = 1 << bitPosition
# Set the bit by performing a bitwise OR operation
result = number | mask
print("Original number:", number)
print("Number with the bit set:", result)
UnSetting a Specific Bit
To unset (clear) the nth
bit in a given number, we will create a mask by performing a left shift on the number 1
by n
positions. This mask will have only the nth
bit set to 1
, with all other bits set to 0
. Next, we will make use bitwise AND. Now we want to unset a particular bit in a number, while leaving all other bits unchanged.
To avoid changing other bits and only change the desired bit, we invert the bits of the mask using the bitwise NOT operation to create a bitmask where all bits are set except for the nth
bit, which is set to 0
. We do this, as performing bitwise AND with 1, gives back the same bit. So we perform a bitwise AND operation between the original number and the bitmask. This operation will clear (unset) the nth
bit in the original number while leaving all other bits unchanged. Here’s a Python code:
bitPosition = 3
number = 10
# Create a mask by left-shifting 1 by bitPosition positions
mask = 1 << bitPosition
# Invert the bits of the mask to create a bitmask
bitmask = ~mask
# Unset the bit by performing a bitwise AND operation
result = number & bitmask
print("Original number:", number)
print("Number with the bit unset:", result)
Toggling a Specific Bit
Toggling a specific bit in a number means changing it from 0
to 1
or from 1
to 0
. We can achieve this by using a bitwise XOR (^) operation. To toggle a bit at a given position, create a mask by performing a left shift on the number 1
by n
positions. This mask will have only the nth
bit set to 1
, with all other bits set to 0
. Now we perform a bitwise XOR operation between the original number and the mask. This operation will toggle the state of the nth
bit in the original number. Here’s the python code:
bitPosition = 3
number = 10
# Create a mask by left-shifting 1 by bitPosition positions
mask = 1 << bitPosition
# Toggle the bit by performing a bitwise XOR operation
result = number ^ mask
print("Original number:", number)
print("Number with the bit toggled:", result)
Checking If a Number is a Power of 2
A number is considered a power of 2
if it has only one bit set to 1
in its binary representation. This property arises from the fact that powers of 2
are represented in binary with only one bit set to 1
and all other bits set to 0
. Here is the code:
if number <= 0:
return False
# Using bitwise AND to check if only one bit is set
return (number & (number - 1)) == 0
In this code, it first checks if the number is less than or equal to 0 because negative numbers and zero cannot be powers of 2. Then, it performs a bitwise AND operation between the number
and its predecessor (number - 1)
. The method is based on the observation that for any number
that is a power of 2, (number - 1)
has ones in positions where the original number has zeroes in its binary representation. So when you perform a bitwise AND operation between a number
and number - 1
, it checks whether there are any common 1s in their binary representations. If there are, the result won’t be 0, indicating that number
is not a power of 2. However, if number
is a power of 2, the bitwise AND operation results in 0 because the binary representation of number
contains only one 1 at the position corresponding to the power of 2, while number - 1
contains all ones except at that position. This outcome confirms that number
is indeed a power of 2.
Let’s take an example using the number 8
. Binary representation of 8
is 1000
. Subtracting 1
from 8
gives 7
, which has a binary representation of 0111
. Now, when we perform the bitwise AND operation between 8
and 7
:
1000 (8 in binary)
& 0111 (7 in binary)
-----------
0000
As expected, the result is 0, confirming that 8 is indeed a power of 2.