Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The ushr (unsigned shift right) operator in Kotlin performs a logical right bitwise shift. It shifts the binary representation of the left operand to the right by the number of bit positions specified by the right operand, filling the newly vacated most significant bits (MSBs) with zeros, regardless of the operand’s original sign.

Syntax

val result = value ushr bitCount

// Alternatively, using standard method invocation:
val result = value.ushr(bitCount)
Because ushr is declared with the infix modifier in Kotlin, it allows omitting the dot and parentheses for readability, though standard method invocation remains perfectly valid.

Technical Mechanics

  • Zero Extension: Unlike the shr (shift right) operator, which performs an arithmetic shift and preserves the sign bit (sign extension), ushr strictly performs a zero extension. This means a negative number shifted using ushr will become a positive number, as the MSB (the sign bit) is overwritten with a 0.
  • Supported Types and the Sign-Extension Trap: The ushr operator is defined exclusively for Int (32-bit) and Long (64-bit) types. It is not defined on smaller types like Byte or Short. Attempting to use ushr directly on these types results in a compiler error (Unresolved reference: ushr). While the operand must be explicitly converted first using .toInt() or .toLong(), doing so on a negative number introduces a semantic bug due to sign extension. Calling .toInt() on a negative Byte pads the new 24 upper bits with 1s. To achieve a true 8-bit or 16-bit logical shift, you must apply a bitwise mask (e.g., and 0xFF) to clear the sign-extended bits before shifting:
val myByte: Byte = -8 // 8-bit binary: 11111000

// val error = myByte ushr 2 // Compiler error

// SEMANTIC BUG: .toInt() sign-extends to 32 bits (11111111 11111111 11111111 11111000)
// Shifting right by 2 yields a massive positive integer instead of an 8-bit shift.
val flawed = myByte.toInt() ushr 2 // Result: 1073741822 (00111111 11111111 11111111 11111110)

// CORRECT: Masking with 0xFF clears the sign-extended bits before the shift.
// 1. myByte.toInt() and 0xFF -> 00000000 00000000 00000000 11111000
// 2. ushr 2                  -> 00000000 00000000 00000000 00111110
val correct = (myByte.toInt() and 0xFF) ushr 2 // Result: 62
  • Shift Distance Masking: Kotlin masks the right operand (bitCount) to prevent shifting beyond the bit-width of the left operand.
    • For an Int, the shift distance is masked with 31 (binary 11111), meaning only the lowest 5 bits of the right operand are used. x ushr 32 is equivalent to x ushr 0.
    • For a Long, the shift distance is masked with 63 (binary 111111), using the lowest 6 bits.

Behavior Visualization

Example 1: Positive Integer

When applied to a positive integer, ushr behaves identically to shr because the MSB is already 0.
val a = 8          // Binary: 00000000 00000000 00000000 00001000
val b = a ushr 2   // Binary: 00000000 00000000 00000000 00000010
// Result: b = 2

Example 2: Negative Integer

When applied to a negative integer, the difference between ushr and shr becomes apparent due to the zero-fill behavior.
val x = -2         // Binary: 11111111 11111111 11111111 11111110
val y = x ushr 1   // Binary: 01111111 11111111 11111111 11111111
// Result: y = 2147483647 (Int.MAX_VALUE)
By contrast, using shr on -2 by 1 would result in -1 (11111111 11111111 11111111 11111111) because it duplicates the 1 in the sign bit.
Master Kotlin with Deep Grasping Methodology!Learn More