Join Our Community

Shift Operators in Java  


Introduction

  • Shift operators in Java are used to shift the bits of integer types (int, long, short, byte, char) either to the left or right, allowing efficient manipulation of binary data.
  • Usage:
    Useful for tasks such as:
    • Low-level programming: Used for manipulating binary data and hardware interaction.
    • Efficient calculations: Scale numbers by powers of two, faster than multiplication/division.
    • Optimizing performance: Faster than arithmetic/logical operations in performance-critical tasks.
    • Data encoding/decoding: Important in bit-packing and handling bits in data.
  • Operation:
    • Binary Manipulation: Shift bits left or right to perform efficient binary tasks.
  • Operand Types:
    • Works only with integer data types (int, long, short, byte and char) but not with floating-point or boolean values.
  • Efficiency:
    • Shift operations are faster than multiplication/division, ideal for performance-critical code.
  • Common Applications:
    • Scaling numbers: Left shift (<<) for multiplication by 2, right shift (>>) for division by 2.
    • Flag manipulation: Combined with bitwise operators for flag management.
    • Memory optimization: Efficiently uses memory, especially with bitmasks.
    • Efficient arithmetic operations: Fast for low-level calculations and cryptography.
  • Shift operators are explained as below :-
    • << (Left shift operator):
      • Purpose: Shifts the bits of a number to the left by the specified number of positions, filling the empty positions with zeros.
      • Effect: Multiplies the number by 2 for each position the bits are shifted.
      • Example:
        int a = 5; 
        System.out.println(a << 1); // Output: 10 (binary 101 << 1 becomes 1010)
    • >> (Right shift operator):
      • Purpose: Shifts the bits of a number to the right by the specified number of positions. The empty positions on the left are filled based on the sign of the number (for signed types).
      • Effect: Divides the number by 2 for each position the bits are shifted, maintaining the sign of the number.
      • Example:
        int a = 20;
        System.out.println(a >> 2); // Output: 5 (binary 10100 >> 2 becomes 101)
    • >>> (Unsigned right shift operator):
      • Purpose: Shifts the bits of a number to the right by the specified number of positions, filling the empty positions with zeros, regardless of the sign.
      • Effect: Divides the number by 2 for each position the bits are shifted but does not preserve the sign.
      • Example:
        int a = -20;
        System.out.println(a >>> 2); // Output: 1073741815 (binary of -20 shifted right with zero-fill)
  • Program:
    public class ShiftOperators
    {
        public static void main(String[] args)
        {
            // Initialize variables
            int a = 5;  // Binary: 0101
            int b = -10; // Binary: 11111111111111111111111111110110 (in 32-bit two's complement)
    
            // Left shift (<<)
            System.out.println("Left Shift (a << 1): " + (a << 1)); // Output: 10 (Binary: 1010)
    
            // Right shift (>>)
            System.out.println("Right Shift (a >> 1): " + (a >> 1)); // Output: 2 (Binary: 0010)
    
            // Unsigned right shift (>>>)
            System.out.println("Unsigned Right Shift (a >>> 1): " + (a >>> 1)); // Output: 2 (Binary: 0010)
    
            // Left shift with negative number
            System.out.println("Left Shift (b << 1): " + (b << 1)); // Output: -20 (Binary: 11111111111111111111111111101100)
    
            // Right shift with negative number
            System.out.println("Right Shift (b >> 1): " + (b >> 1)); // Output: -5 (Binary: 11111111111111111111111111111011)
    
            // Unsigned right shift with negative number
            System.out.println("Unsigned Right Shift (b >>> 1): " + (b >>> 1)); // Output: 2147483643 (Binary: 01111111111111111111111111111011)
        }
    }
    Output:
    Left Shift (a << 1): 10
    Right Shift (a >> 1): 2
    Unsigned Right Shift (a >>> 1): 2
    Left Shift (b << 1): -20
    Right Shift (b >> 1): -5
    Unsigned Right Shift (b >>> 1): 2147483643
Some Advance Important Points :-
  • Shift Operators with Literals:
    • Shift operators can be directly applied to literals or variables.
    • Example:
      System.out.println(4 << 2); // Output: 16 (Binary: 0100 << 2 positions results in 10000)
      System.out.println(8 >> 1); // Output: 4 (Binary: 1000 >> 1 position results in 0100)
  • Supported Data Types:
    • Shift operators work only with integer types such as byte, short, int, long and char.
    • Applying shift operators to floating-point types (float, double) will result in a compilation error.
      System.out.println(5.5 << 1); // Compilation error: incompatible types: possible lossy conversion from double to int
  • Left Shift (<<) for Multiplication:
    • The left shift operator (<<) is used for efficient multiplication by powers of two.
    • Example :
      int x = 3;
      System.out.println(x << 2); // Output: 12 (Equivalent to 3 * 2^2)
    • This is computationally faster than using multiplication (x * 4).
  • Right Shift (>>) for Division:
    • The right shift operator (>>) is used for efficient division by powers of two.
    • Example :
      int x = 16;
      System.out.println(x >> 2); // Output: 4 (Equivalent to 16 / 2^2)
    • This is faster than using division (x / 4).
  • Unsigned Right Shift (>>>) and Negative Numbers:
    • The unsigned right shift operator (>>>) behaves differently for negative numbers by filling with zeros instead of extending the sign bit.
    • Example :
      int x = -8; 
      System.out.println(x >>> 1); // Output: 2147483640 (In binary: 11111111111111111111111111111000 >> 1 results in 01111111111111111111111111111100)
  • Shift Operators with Negative Numbers:
    • The behavior of shift operators is distinct when applied to negative numbers, especially the sign extension in the right shift (>>).
    • The left shift (<<) of a negative number behaves the same as for positive numbers but can result in sign changes if the leftmost bit is shifted into the sign bit.
    • Example :
      int x = -5;
      System.out.println(x << 1); // Output: -10 (Binary: 11111111111111111111111111111011 << 1 results in 11111111111111111111111111110110)
  • Zero-Fill Right Shift (>>>) with Negative Numbers:
    • The unsigned right shift (>>>) on negative numbers replaces the sign bit with 0, making it useful for operations like bit masks or extracting specific parts of a number.
    • Example:
      int x = -4;
      System.out.println(x >>> 1); // Output: 2147483643 (Binary: 11111111111111111111111111111100 >>> 1 results in 01111111111111111111111111111110)
  • Shifting on Larger Numbers (long):
    • The shift operators can be used on larger integer types like long. However, the right operand should be masked with & 0x3F (for long shift) to avoid shifting more than 63 positions (for 64-bit long).
    • Example:
      long x = 100L;
      System.out.println(x << 3); // Output: 800 (Equivalent to 100 * 2^3)
  • Shift Operations with Negative Powers:
    • Negative values in the right shift operator (>> and >>>) will throw a compile-time error.
    • Example:
      int x = 8;
      System.out.println(x >> -2); // Compile-time error: shift count must be non-negative
  • Overflow and Underflow in Shift Operations:
    • While shifting, if the value overflows or underflows beyond the range of the data type, the result can be unpredictable. Javaโ€™s shift operators do not raise errors for overflows but wrap the result around based on the data type size.
    • Example:
      int x = Integer.MAX_VALUE;
      System.out.println(x << 1); // Output: -2 (Overflow: 2147483647 << 1 results in a negative value)


Advertisements