Open In App

Right Shift Operator (>>) in Programming

Right shift operator (>>), commonly found in programming languages, including C, C++, Java, and others, is used to shift the bits of a number to the right by a specified number of positions. Each shift moves all bits in the operand to the right by the number of positions indicated by the right operand.

This comprehensive guide aims to provide a deep understanding of bitwise right shift operators, from the foundational principles to advanced optimization strategies.

Right Shift Operator (>>) Definition:

When you right-shift a binary number by n positions, each bit in the number is moved n positions to the right. This effectively divides the number by 2^n (equivalent to integer division by 2^n). The rightmost n bits are discarded, and 0 bits are shifted in from the left.

Right Shift Operator (>>) Syntax:

The syntax of the bitwise right shift operator is simple and consistent across programming languages:

operand >> n

Where:

Right Shift Operator (>>) Examples:

Consider the binary number 1101 0010, which is 210 in decimal. If we right-shift it by 2 positions:

1101 0010 >> 2

The result would be 0011 0100, which is 52 in decimal. This is because each bit is shifted two positions to the right, and the vacant positions on the left are filled with 0s.

#include <iostream>
using namespace std;

int main()
{
    // Binary representation: 11010010
    int num = 210; 
    int shifted_num = num >> 2;
    cout << shifted_num << endl;
    return 0;
}
#include <stdio.h>

int main() {
    // Binary representation: 11010010
    int num = 210;
    int shifted_num = num >> 2;
    printf("%d\n", shifted_num);
    return 0;
}
/* package whatever // do not write package name here */

import java.io.*;

class GFG {
    public static void main(String[] args) {
        // Binary representation: 11010010
        int num = 210;
        int shiftedNum = num >> 2;
        System.out.println(shiftedNum);
    }
}
# Binary representation: 11010010
num = 210
shifted_num = num >> 2
print(shifted_num)
using System;

class Program {
    static void Main()
    {
        // Binary representation: 11010010
        int num = 210;
        int shiftedNum = num >>2;
        Console.WriteLine(shiftedNum);
    }
}
// Binary representation: 11010010
let num = 210;
let shiftedNum = num>>2;
console.log(shiftedNum);

Output
52

Right Shift Operator (>>) with Signed Integers:

When using the bitwise right shift (>>) operator with signed integers, it's essential to understand how the sign bit is preserved and the implications of this preservation. Let's explore this with examples:

Preserving Sign Bit:

In signed integers, the leftmost bit (most significant bit) represents the sign of the number. When right-shifting signed integers, the sign bit is preserved, meaning it is replicated to fill the vacant leftmost positions.

Example:

# Signed right shift
x = -8 # Binary: 1111 1000 (assuming 8-bit signed integer)
y = x >> 1 # Binary: 1111 1100, Decimal: -4

In this example, when -8 is right-shifted by 1 position, the sign bit (1) is replicated, resulting in 1111 1100, which represents -4 in decimal.

Use Case: Division by Powers of 2 with Signed Integers

#include <iostream>

int main() {
    int num = -16;
    int divisor = 4;
    int result = num >> 2; // Equivalent to num / 2^2
    std::cout << result << std::endl; // Output: -4
    return 0;
}
public class Main {
    public static void main(String[] args) {
        int num = -16;
        int divisor = 4;
        int result = num >> 2; // Equivalent to num / 2^2
        System.out.println(result); // Output: -4
    }
}
# Division by powers of 2 using right shift with signed integers
num = -16
divisor = 4
result = num >> 2 # Equivalent to num // 2**2
print(result) # Output: -4
using System;

class Program
{
    static void Main(string[] args)
    {
        int num = -16;
        int result = num >> 2; // Equivalent to num / 2^2
        Console.WriteLine(result); // Output: -4
    }
}
//This code is contributed by Adarsh.
// JavaScript pprogram 

// Main function
function main() {
    let num = -16;
    let result = num >> 2; // Equivalent to num / 2^2
    console.log(result);  
}

// Call the main function to execute the program
main();

Output
-4

In this case, -16 is right-shifted by 2 positions, which is equivalent to dividing -16 by 2**2. The sign bit is preserved during the right shift, resulting in -4.

Right Shift Operator (>>) with Unsigned Integers:

When using the bitwise right shift (>>) operator with unsigned integers, the behavior is simpler compared to signed integers. Let's explore how the right shift operator works with unsigned integers:

Behavior with Unsigned Integers:

In unsigned integers, there is no sign bit, so the right shift operation simply shifts the bits to the right, filling the vacant leftmost positions with zeros.

Example:

# Division by powers of 2 using right shift with unsigned integers
num = 16
divisor = 4
result = num >> 2 # Equivalent to num // 2**2
print(result) # Output: 4

In this example, when the unsigned integer 8 is right-shifted by 1 position, the bits are shifted to the right, and the vacant leftmost position is filled with 0, resulting in 0000 0100, which represents 4 in decimal.

Use Case: Division by Powers of 2 with Unsigned Integers

#include <iostream>
using namespace std;

int main() {
    unsigned int num = 16;
    unsigned int divisor = 4;
    unsigned int result = num >> 2; // Equivalent to num / 2^2
    cout << result << endl; // Output: 4

    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        // Initialize variables
        int num = 16;
        int divisor = 4; 

        // Right shift operator (>>), equivalent to division by 2^divisor
        int result = num >>2; // Equivalent to num / 2^divisor
        System.out.println(result); // Output: 4
    }
}
# Division by powers of 2 using right shift with unsigned integers
num = 16
divisor = 4
result = num>>2  # Equivalent to num // 2**2
print(result)  # Output: 4
// Initialize variables
let num = 16;
let divisor = 4;

// Right shift operator (>>), equivalent to division by 2^divisor
let result = num >>2; // Equivalent to num / 2^divisor
console.log(result); // Output: 4

Output
4

In this case, 16 is an unsigned integer, and right-shifting it by 2 positions is equivalent to dividing 16 by 2**2. The bits are simply shifted to the right, filling the vacant leftmost positions with zeros, resulting in 0000 0100, which represents 4 in decimal.

Right Shift Operator (>>) with Signed vs. Unsigned Integers:

AspectSigned IntegersUnsigned Integers
Sign Bit PreservationSign bit is preserved, replicated to fill vacant leftmost positions.No sign bit, all bits are shifted to the right, filling vacant positions with zeros.
Example-8 >> 1 results in -4 (Binary: 1111 1100)8 >> 1 results in 4 (Binary: 0000 0100)
Division by Powers of 2Right shift performs signed division by 2^n.Right shift performs unsigned division by 2^n.
Implementation in ProgrammingBehavior depends on language and compiler. Most use arithmetic right shift.Always performs logical right shift.

Logical Right Shift:

Bitwise logical right shift refers to the operation of shifting the bits of a binary number to the right by a specified number of positions while filling the vacant leftmost positions with zeros. This operation is commonly used with unsigned integers and is denoted by the >> operator in most programming languages.

Syntax:

operand >> n


Where operand is the value whose bits are to be shifted, and n is the number of positions to shift by.

Example:

# Logical right shift
x = 8 # Binary: 0000 1000
y = x >> 1 # Binary: 0000 0100, Decimal: 4

Use Cases:

  1. Unsigned Integer Division by Powers of 2: Logical right shift can be used to divide unsigned integers by powers of 2 efficiently.
  2. Clearing Bits: Logical right shift is useful for clearing specific bits in a binary number, as shifting bits to the right fills the vacant leftmost positions with zeros.

Arithmetic Right Shift:

Bitwise arithmetic right shift is an operation used to shift the bits of a binary number to the right by a specified number of positions while preserving the sign of the number. This operation is commonly used with signed integers and is denoted by the >> operator in many programming languages.

Syntax:

operand >> n

Where operand is the value whose bits are to be shifted, and n is the number of positions to shift by.

Example:

# Arithmetic right shift
x = -8 # Binary: 1111 1000 (assuming 8-bit signed integer)
y = x >> 1 # Binary: 1111 1100, Decimal: -4

Use Cases:

  1. Signed Integer Division by Powers of 2: Arithmetic right shift can be used to divide signed integers by powers of 2 efficiently while preserving the sign of the number.
  2. Preserving Sign Bit: Unlike logical right shift, arithmetic right shift preserves the sign bit, ensuring that the sign of the number remains unchanged.

Logical Right Shift vs. Arithmetic Right Shift:

Let's summarize the differences between bitwise logical right shift (>>) and bitwise arithmetic right shift (>>) in a table:

AspectLogical Right Shift (unsigned integers)Arithmetic Right Shift (signed integers)
Sign PreservationDoes not preserve sign; fills vacant leftmost positions with zeros.Preserves sign; replicates sign bit to fill vacant leftmost positions.
Example8 >> 1 results in 4 (Binary: 0000 0100)-8 >> 1 results in -4 (Binary: 1111 1100)
Division by Powers of 2Performs unsigned division by 2^n.Performs signed division by 2^n.
Implementation in ProgrammingPerforms logical right shift, filling vacant positions with zeros.Performs arithmetic right shift, preserving the sign bit.

Right Shift Operator (>>) Optimization Techniques:

1. Division by Powers of 2:

Right shifting a number by n positions is equivalent to dividing it by 2^n. This property is extensively used for optimization in situations where division by powers of 2 is required.

Example: In low-level programming or embedded systems, when dealing with hardware registers or memory addresses that are aligned to powers of 2, right shifting can be used to divide them effectively.

# Division by powers of 2 using right shift
num = 64
divisor = 4
result = num>>2  # Equivalent to num // 2**2
print(result)  # Output: 16

Output
16

2. Faster Arithmetic Operations:

Right shifts are often utilized to optimize arithmetic operations, particularly in performance-critical applications.

Example: In algorithms where performance is critical, such as numerical computations or graphics rendering, replacing division by powers of 2 with right shifts can lead to significant performance gains.

# Optimizing arithmetic operations with right shift
def multiply_by_power_of_2(x, power):
    return x << power  # Equivalent to x * 2**power

result = multiply_by_power_of_2(5, 3)  # 5 * 2**3
print(result)  # Output: 40

Output
40

3. Data Compression:

Bitwise operations, including right shifts, play a crucial role in data compression algorithms.

Example: In Huffman coding, right shifting can be used to encode symbols efficiently, especially when dealing with probabilities that are powers of 2.

# Huffman coding using right shift for encoding
frequency = 16  # Assume frequency of a symbol
encoded_value = frequency>>3  # Huffman encoding based on frequency
print(encoded_value)

Output
2

4. Bit Manipulation:

Right shifts are fundamental for various bit manipulation tasks, such as extracting specific bits, checking bit flags, or packing/unpacking data structures.

Example: In networking protocols, when parsing headers, right shifting can be used to extract fields representing packet lengths, checksums, or protocol version numbers.

# Extracting specific bits using right shift and bitwise AND
flags = 0b10101010
bit_mask = 0b00001111  # Extract lower nibble
extracted_bits = (flags >> 4) & bit_mask
print(bin(extracted_bits))  # Output: 0b1010

Output
0b1010

5. Masking and Filtering:

Right shifting can be combined with bitwise AND (&) to create masks for filtering out specific bits or extracting certain bit patterns.

Example: In image processing, right shifting can be used to reduce the color depth of an image by discarding the least significant bits, effectively creating a lower-resolution version of the image.

# Masking to filter out specific bits using right shift and bitwise AND
value = 0b11001100
mask = 0b11110000  # Mask to keep only the upper nibble
filtered_value = value & mask
print(bin(filtered_value))  # Output: 0b11000000

Output
0b11000000

6. Encryption and Hashing:

Right shifts are employed in various cryptographic algorithms for bitwise mixing and diffusion of data.

Example: In block ciphers like AES (Advanced Encryption Standard), right shifts are part of the key expansion and encryption/decryption operations.

# Encryption operation using right shift
def encrypt_data(data, key):
    encrypted_data = data ^ key  # XOR operation for encryption
    return encrypted_data

# Decrypt the data using the same key
def decrypt_data(encrypted_data, key):
    decrypted_data = encrypted_data ^ key  # XOR operation for decryption
    return decrypted_data

data = 0b10101010
key = 0b11110000
encrypted = encrypt_data(data, key)
decrypted = decrypt_data(encrypted, key)
print(bin(encrypted))  # Output: 0b01011010
print(bin(decrypted))  # Output: 0b10101010

Output
0b1011010
0b10101010

7. Fixed-Point Arithmetic:

Right shifts are used in fixed-point arithmetic to perform fractional division by powers of 2.

Example: In digital signal processing (DSP) applications, when working with fixed-point numbers, right shifts can be used to scale the result of mathematical operations.

# Fixed-point arithmetic with right shift
def fixed_point_division(num, divisor, fraction_bits):
    scaled_num = num << fraction_bits  # Scale numerator
    result = scaled_num // divisor
    return result

numerator = 25
divisor = 4
fraction_bits = 2
result = fixed_point_division(numerator, divisor, fraction_bits)
print(result)  # Output: 100 (Equivalent to 25 / 4)

Output
25

Bit Manipulation Hacks with Right Shift Operator:

Bitwise right shift (>>) is a fundamental operation in bit manipulation and bit twiddling hacks. It is often used in combination with other bitwise operators to achieve various tasks efficiently. Here are some common bit manipulation and bit twiddling hacks that involve bitwise right shift:

1. Setting or Clearing Bits:

In set_bit, the bitwise OR operation (|) with (1 << n) sets the nth bit of the number to 1. In clear_bit, the bitwise AND operation (&) with the complement of (1 << n) clears the nth bit of the number.

#include <stdio.h>

// Setting the nth bit of a number
unsigned int set_bit(unsigned int num, int n) {
    return num | (1 << n);
}

// Clearing the nth bit of a number
unsigned int clear_bit(unsigned int num, int n) {
    return num & ~(1 << n);
}

int main() {
    unsigned int num = 10; // Binary: 1010
    printf("Set bit at position 2: %u\n", set_bit(num, 2)); // Output: 14 (Binary: 1110)
    printf("Clear bit at position 3: %u\n", clear_bit(num, 3)); // Output: 2 (Binary: 0010)
    return 0;
}

Output
Set bit at position 2: 14
Clear bit at position 3: 2

2. Checking if a Number is a Power of 2:

A number is a power of 2 if it has only one bit set. The expression (num & (num - 1)) clears the lowest set bit, so if the result is zero and the number is not zero, then it is a power of 2.

#include <stdio.h>
#include <stdbool.h>

// Checking if a number is a power of 2
bool is_power_of_2(unsigned int num) {
    return (num != 0) && ((num & (num - 1)) == 0);
}

int main() {
    unsigned int num = 16; // Binary: 10000
    printf("%d\n", is_power_of_2(num)); // Output: true (1)
    return 0;
}

Output
1

3. Counting Set Bits (Population Count):

The loop iterates through each bit of the number and counts the bits that are set to 1 using the bitwise AND operation (&) with 1.

#include <stdio.h>

// Counting the number of set bits in a number
int count_set_bits(unsigned int num) {
    int count = 0;
    while (num) {
        count += num & 1;
        num >>= 1;
    }
    return count;
}

int main() {
    unsigned int num = 15; // Binary: 1111
    printf("Number of set bits: %d\n", count_set_bits(num)); // Output: 4
    return 0;
}

Output
Number of set bits: 4

4. Extracting the Lowest Set Bit:

The expression num & -num isolates the lowest set bit of the number by preserving only that bit and setting all other bits to 0.

#include <stdio.h>

// Extracting the lowest set bit of a number
unsigned int extract_lowest_set_bit(unsigned int num) {
    return num & -num;
}

int main() {
    unsigned int num = 14; // Binary: 1110
    printf("Lowest set bit: %u\n", extract_lowest_set_bit(num)); // Output: 2 (Binary: 0010)
    return 0;
}

Output
Lowest set bit: 2

5. Rotating Bits:

The expression (num >> n) | (num << (sizeof(num) * 8 - n)) rotates the bits of the number to the right by n positions.

#include <stdio.h>

// Rotating bits to the right by n positions
unsigned int rotate_right(unsigned int num, int n) {
    return (num >> n) | (num << (sizeof(num) * 8 - n));
}

int main() {
    unsigned int num = 10; // Binary: 1010
    printf("Rotated right by 2 positions: %u\n", rotate_right(num, 2)); // Output: 40 (Binary: 101000)
    return 0;
}

Output
Rotated right by 2 positions: 2147483650

6. Reversing Bits:

The loop iterates through each bit of the number, shifting and adding the bits to the reversed number to reverse them.

#include <iostream>

// Reversing the bits of a number
unsigned int reverseBits(unsigned int num)
{
    unsigned int reversedNum = 0;
    while (num) {
        reversedNum <<= 1;
        reversedNum |= num & 1;
        num >>= 1;
    }
    return reversedNum;
}

int main()
{
    unsigned int num = 10; // Binary: 1010
    std::cout << "Reversed bits: " << reverseBits(num)
              << std::endl; // Output: 5 (Binary: 0101)
    return 0;
}
#include <stdio.h>

// Reversing the bits of a number
unsigned int reverse_bits(unsigned int num)
{
    unsigned int reversed_num = 0;
    while (num) {
        reversed_num <<= 1;
        reversed_num |= num & 1;
        num >>= 1;
    }
    return reversed_num;
}

int main()
{
    unsigned int num = 10; // Binary: 1010
    printf("Reversed bits: %u\n",
           reverse_bits(num)); // Output: 5 (Binary: 0101)
    return 0;
}
public class Main {
    // Function to reverse the bits of a number
    static int reverseBits(int num)
    {
        int reversedNum = 0;
        while (num != 0) {
            // Shift the reversed number left by 1 position
            reversedNum <<= 1;
            // Add the least significant bit of num to
            // reversedNum
            reversedNum |= num & 1;
            // Shift num right by 1 position
            num >>= 1;
        }
        return reversedNum;
    }

    public static void main(String[] args)
    {
        int num = 10; // Binary: 1010
        System.out.println(
            "Reversed bits: "
            + reverseBits(num)); // Output: 5 (Binary: 0101)
    }
}
# Reversing the bits of a number
def reverse_bits(num):
    reversed_num = 0
    while num:
        reversed_num <<= 1
        reversed_num |= num & 1
        num >>= 1
    return reversed_num


def main():
    num = 10  # Binary: 1010
    print("Reversed bits:", reverse_bits(num))  # Output: 5 (Binary: 0101)


if __name__ == "__main__":
    main()
function reverseBits(num) {
    let reversedNum = 0;
    while (num !== 0) {
        // Shift the reversed number left by 1 position
        reversedNum <<= 1;
        // Add the least significant bit of num to reversedNum
        reversedNum |= num & 1;
        // Shift num right by 1 position
        num >>= 1;
    }
    return reversedNum;
}

// Test the function
let num = 10; // Binary: 1010
console.log("Reversed bits: " + reverseBits(num)); // Output: 5 (Binary: 0101)

Output
Reversed bits: 5


Article Tags :