What is (x & 1) and (x >>= 1)?
Categories:
Understanding Bitwise Operations: x & 1
and x >>= 1

Explore the fundamental bitwise operators &
(AND) and >>=
(right shift assignment) in C++. Learn how they are used for efficient bit manipulation, such as checking parity and performing division by powers of two.
Bitwise operations are a powerful and often misunderstood aspect of low-level programming. They allow direct manipulation of individual bits within an integer, offering highly efficient ways to perform certain tasks that might otherwise require more complex arithmetic or conditional logic. This article delves into two common bitwise expressions: x & 1
and x >>= 1
, explaining their purpose, how they work, and practical applications.
The Bitwise AND Operator: x & 1
The bitwise AND operator (&
) compares corresponding bits of two operands. If both bits are 1, the resulting bit is 1; otherwise, it's 0. When you perform x & 1
, you are essentially checking the least significant bit (LSB) of x
. The number 1
in binary is ...0001
. Therefore, x & 1
will result in 1
if the LSB of x
is 1
(meaning x
is odd), and 0
if the LSB of x
is 0
(meaning x
is even).
flowchart LR subgraph x & 1 A["Input x (e.g., 5)"] --> B{Binary: 101} C["Input 1"] --> D{Binary: 001} B -- "Bitwise AND (&)" --> E["Result: 001"] D -- "Bitwise AND (&)" --> E E --> F["Decimal: 1"] end subgraph x & 1 G["Input x (e.g., 4)"] --> H{Binary: 100} I["Input 1"] --> J{Binary: 001} H -- "Bitwise AND (&)" --> K["Result: 000"] J -- "Bitwise AND (&)" --> K K --> L["Decimal: 0"] end
Flowchart illustrating x & 1
for odd and even numbers.
#include <iostream>
int main() {
int num1 = 5; // Binary: ...0101
int num2 = 4; // Binary: ...0100
std::cout << num1 << " & 1 = " << (num1 & 1) << std::endl; // Output: 1
std::cout << num2 << " & 1 = " << (num2 & 1) << std::endl; // Output: 0
if ((num1 & 1) == 1) {
std::cout << num1 << " is odd." << std::endl;
} else {
std::cout << num1 << " is even." << std::endl;
}
return 0;
}
C++ example demonstrating x & 1
to check for odd/even numbers.
x & 1
is often more efficient than the modulo operator (x % 2
) for checking parity, especially in performance-critical applications, as bitwise operations are typically executed directly by the CPU.The Right Shift Assignment Operator: x >>= 1
The right shift operator (>>
) shifts the bits of its left operand to the right by the number of positions specified by its right operand. The >>=
operator is a compound assignment operator, meaning x >>= 1
is equivalent to x = x >> 1
. When you right-shift an integer by one position, you are effectively dividing it by 2. For unsigned integers, zeros are shifted in from the left. For signed integers, the behavior of the most significant bit (sign bit) depends on the implementation (arithmetic shift vs. logical shift), but for positive numbers, it generally behaves like an unsigned shift, filling with zeros. For negative numbers, it typically preserves the sign bit (arithmetic shift), filling with ones.
flowchart LR A["Input x (e.g., 10)"] --> B{"Binary: 1010"} B -- "Right Shift by 1 (>>= 1)" --> C{"Shifted: 0101"} C --> D["Decimal: 5"] E["Input x (e.g., 7)"] --> F{"Binary: 0111"} F -- "Right Shift by 1 (>>= 1)" --> G{"Shifted: 0011"} G --> H["Decimal: 3"] style A fill:#f9f,stroke:#333,stroke-width:2px style E fill:#f9f,stroke:#333,stroke-width:2px
Visualizing the x >>= 1
operation.
#include <iostream>
int main() {
int num = 10; // Binary: ...1010
std::cout << "Initial num: " << num << std::endl; // Output: 10
num >>= 1; // num becomes 5 (Binary: ...0101)
std::cout << "num after >>= 1: " << num << std::endl; // Output: 5
num >>= 1; // num becomes 2 (Binary: ...0010)
std::cout << "num after another >>= 1: " << num << std::endl; // Output: 2
unsigned int u_num = 15; // Binary: ...1111
std::cout << "\nInitial unsigned num: " << u_num << std::endl; // Output: 15
u_num >>= 1; // u_num becomes 7 (Binary: ...0111)
std::cout << "unsigned num after >>= 1: " << u_num << std::endl; // Output: 7
return 0;
}
C++ example demonstrating x >>= 1
for integer division.
>>=
with negative signed integers. While it typically performs an arithmetic right shift (preserving the sign bit), the exact behavior for negative numbers can be implementation-defined before C++20. For reliable division by 2 for negative numbers, consider x / 2
or explicitly handle the sign.Combining x & 1
and x >>= 1
for Iterative Bit Processing
These two operators are frequently used together in algorithms that process an integer bit by bit, often from the least significant bit upwards. A classic example is counting the number of set bits (1s) in an integer or converting a decimal number to its binary representation.
#include <iostream>
int main() {
int num = 13; // Binary: 1101
int set_bits_count = 0;
std::cout << "Processing number: " << num << std::endl;
while (num > 0) {
// Check if the LSB is 1
if ((num & 1) == 1) {
set_bits_count++;
std::cout << " LSB is 1. Count: " << set_bits_count << std::endl;
} else {
std::cout << " LSB is 0." << std::endl;
}
// Shift right to process the next bit
num >>= 1;
std::cout << " Number after shift: " << num << std::endl;
}
std::cout << "Total set bits: " << set_bits_count << std::endl; // Output: 3
return 0;
}
C++ example counting set bits using x & 1
and x >>= 1
.
In this loop, num & 1
extracts the value of the current LSB, and num >>= 1
discards that LSB and brings the next bit into the LSB position for the next iteration. This process continues until num
becomes 0, meaning all bits have been processed.