You are currently viewing Swift Bitwise Operators

Swift Bitwise Operators

Swift, Apple’s powerful and intuitive programming language, provides a set of bitwise operators that allow developers to manipulate individual bits within binary representations of data. Understanding and effectively using these operators can significantly enhance your ability to perform low-level operations, optimize code, and implement certain algorithms efficiently. In this article, we will explore Swift bitwise operators, and provide code examples to help you understand their usage.

Understanding Bits and Binary Representation

Before exploring Swift’s bitwise operators, it’s crucial to understand the basics of binary representation. In the binary system, all data is expressed using only two digits: 0 and 1. A single binary digit is called a bit, and eight bits make up a byte. These bytes can represent various types of data, from integers to characters and more.

Swift provides several bitwise operators that allow you to manipulate individual bits within these binary representations. The main bitwise operators are AND (&), OR (|), XOR (^), NOT (~), left shift (<<), and right shift (>>).

Bitwise AND Operator (&)

The AND operator (&) combines two binary numbers, producing a result where each bit is set to 1 only if both corresponding bits are 1. Here’s an example:

let a: UInt8 = 0b10101010
let b: UInt8 = 0b11001100

let result = a & b // Output: 0b10001000

print(String(result, radix: 2))

In this example, the result is obtained by performing the AND operation on each pair of corresponding bits in a and b. Only bits that are set to 1 in both a and b contribute to the result.

Checking Even or Odd

The least significant bit of a binary number determines whether the number is even or odd. If the bit is 0, the number is even; if it’s 1, the number is odd. We can use the bitwise AND operator to check this:

func isEven(number: Int) -> Bool {
    return (number & 1) == 0
}

func isOdd(number: Int) -> Bool {
    return (number & 1) == 1
}

let number = 7

let even = isEven(number: number)
print("\(number) is an even number: \(even).")

let odd = isOdd(number: number)
print("\(number) is an odd number: \(odd).")

Bitwise OR Operator (|)

The OR operator (|) combines two binary numbers, producing a result where each bit is set to 1 if at least one of the corresponding bits is 1:

let a: UInt8 = 0b10101010
let b: UInt8 = 0b11001100

let result = a | b // Output: 0b11101110

print(String(result, radix: 2))

Here, the OR operation results in a binary number where any position with a 1 in either a or b contributes to the final output.

Bitwise XOR Operator (^)

The XOR operator (^) combines two binary numbers, producing a result where each bit is set to 1 only if the corresponding bits are different:

let a: UInt8 = 0b10101010
let b: UInt8 = 0b11001100

let result = a ^ b // Output: 0b01100110

print(String(result, radix: 2))

In this case, the XOR operation produces a binary number where bits that are the same in both a and b become 0, while bits that are different become 1.

Swapping Values

Bitwise XOR can be used to swap the values of two variables without using a temporary variable:

var a: Int = 5
var b: Int = 8

print("BEFORE SWAP: {a: \(a), b: \(b)}")

a = a ^ b
b = a ^ b
a = a ^ b

print("AFTER SWAP: {a: \(a), b: \(b)}")

Bitwise NOT Operator (~)

The NOT operator (~) inverts the bits of a binary number, turning 0s into 1s and 1s into 0s:

let a: UInt8 = 0b10101010

let result = ~a // Output: 0b01010101

print(String(result, radix: 2))

The NOT operation flips all the bits in the binary representation of a.

Bitwise Left Shift Operator (<<)

The left shift operator, denoted by the double less-than (<<) symbol, shifts the bits of a number to the left by a specified number of positions.

let a: UInt8 = 0b10101010

let leftShifted = a << 2 // Output: 0b1010101000

print(String(leftShifted, radix: 2))

In this example, the bits of a are shifted two positions to the left, with zeros filling in the vacant positions. This operation is equivalent to multiplying the number by 2 raised to the power of the shift amount. Therefore, in this case, a << 2 is equivalent to a * (2^2).

Bitwise Right Shift Operator (>>)

The right shift operator, represented by the double greater-than (>>) symbol, shifts the bits of a number to the right by a specified number of positions.

let a: UInt8 = 0b10101010

let rightShifted = a >> 2 // Output: 0b00101010

print(String(rightShifted, radix: 2))

In this example, the bits are shifted two positions to the right, and the vacant positions are filled with zeros. This operation is equivalent to dividing the number by 2 raised to the power of the shift amount. Therefore, in this case, a >> 2 is equivalent to a / (2^2).

Bitwise Left Shift with Overflow Check (&<<)

Swift provides a safer version of the bitwise left shift with the &<< operator, which performs the shift while checking for overflow. Overflow can occur if the shifted bits extend beyond the capacity of the data type. Let’s see how this operator works in practice:

let a: UInt8 = UInt8.max
let shiftedValue = a &<< 2

print("Shifted value: \(shiftedValue)")

In this example, a is set to the maximum value that a UInt8 can hold. The &<< 2 operation shifts the bits two positions to the left. However, if this operation would result in overflow, Swift ensures that the result is a valid value within the data type’s capacity. The output remains within the valid range, preventing unexpected behavior.

Bitwise Right Shift with Overflow Check (&>>)

Similarly, the &>> operator performs a bitwise right shift while checking for overflow. Here’s an example:

let a: UInt8 = UInt8.min
let shiftedValue: UInt8 = a &>> 2

print("Shifted value: \(shiftedValue)")

In this example, a is set to the minimum value that a UInt8 can hold. The &>> 2 operation shifts the bits two positions to the right, checking for overflow. If the operation would result in overflow, Swift adjusts the result to stay within the valid range for the data type. This ensures the reliability of your code, especially when dealing with critical numerical operations.

Precedence of Bitwise Operators

Basic understanding of operator precedence is essential for writing correct and efficient code. Bitwise operators in Swift follow the standard precedence rules, where NOT (~) has the highest precedence, followed by Shift Operators (Left Shift <<, and Right Shift >>), AND (&), XOR (^), and OR (|).

let result = 0b10101010 & 0b11001100 ^ 0b11110000 | 0b00110011 // Equivalent to: (((0b10101010 & 0b11001100) ^ 0b11110000) | 0b00110011)

print(String(result, radix: 2))

In this example, as shown in the comments, parentheses are used to explicitly define the order of operations based on precedence. It is advisable to always use parentheses to specify your intent.

Conclusion

Swift’s bitwise operators provide a powerful toolset for low-level bit manipulation, allowing developers to optimize code, implement efficient algorithms, and perform various tasks that require a deep understanding of binary representation.

Sources:

Leave a Reply