TypeScript, a superset of JavaScript, includes a set of bitwise operators that allow developers to perform bitwise manipulation on integer values. Bitwise operators manipulate the individual bits of binary numbers, providing a low-level, efficient way to perform certain operations. In this article, we will explore TypeScript’s bitwise operators, and provide code examples to solidify your understanding.
What Are Bitwise Operators?
Bitwise operators are a set of operations that directly manipulate individual bits of binary numbers. In TypeScript, as in many other programming languages, bitwise operators operate on integers. These operators provide a way to perform low-level operations efficiently, such as bit manipulation, flag setting, and more.
Bitwise AND Operator (&)
The bitwise AND operator compares each bit of the first operand to the corresponding bit of the second operand. If both bits are 1, the resulting bit will be 1; otherwise, it will be 0.
const result: number = 5 & 3; // Binary: 0101 & 0011
console.log(result); // Output: 1
In binary, 5 is 101, and 3 is 011. Performing a bitwise AND operation on corresponding bits yields 001, which is 1 in decimal.
Bitwise OR Operator (|)
The bitwise OR operator compares each bit of the first operand to the corresponding bit of the second operand. If either bit is 1, the resulting bit will be 1; otherwise, it will be 0.
const result: number = 5 | 3; // Binary: 0101 | 0011
console.log(result); // Output: 7
In binary, 5 is 101, and 3 is 011. Performing a bitwise OR operation on corresponding bits yields 111, which is 7 in decimal.
Bitwise XOR Operator (^)
The bitwise XOR (exclusive OR) operator compares each bit of the first operand to the corresponding bit of the second operand. If the bits are different, the resulting bit will be 1; otherwise, it will be 0.
const result: number = 5 ^ 3; // Binary: 0101 ^ 0011
console.log(result); // Output: 6
In binary, 5 is 101, and 3 is 011. Performing a bitwise XOR operation on corresponding bits yields 110, which is 6 in decimal.
Swapping Values
Bitwise XOR can be used to swap the values of two variables without using a temporary variable.
let a: number = 5;
let b: number = 10;
console.log(BEFORE SWAP: {a: ${a}, b: ${b}});
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(AFTER SWAP: {a: ${a}, b: ${b}});
Bitwise NOT Operator (~)
The bitwise NOT operator inverts each bit of its operand. It transforms 1s into 0s and 0s into 1s.
const result: number = ~5; // Binary: ~0101
console.log(result); // Output: -6
Note that the result is a negative number due to the two’s complement representation of negative integers. However, the exact value is not essential in this context; what matters is the inverted bit pattern.
Bitwise Left Shift Operator (<<)
The left shift operator shifts the bits of the first operand to the left by the number of positions specified by the second operand. This operation is equivalent to multiplying the first operand by 2 raised to the power of the second operand.
const result: number = 5 << 1; // Binary: 0101 << 1
console.log(result); // Output: 10
In this example, the binary representation of 5 is shifted two positions to the left, effectively multiplying it by 2^1 (2).
Bitwise Right Shift Operator (>>)
The right shift operator shifts the bits of the first operand to the right by the number of positions specified by the second operand. This operation is equivalent to dividing the first operand by 2 raised to the power of the second operand.
const result: number = 5 >> 1; // Binary: 0101 >> 1
console.log(result); // Output: 2
Here, the binary representation of 5 is shifted two positions to the right, effectively dividing it by 2^1 (1), discarding the fractional part.
Counting Set Bits
You can use bitwise operations to count the number of set bits (1s) in a binary representation.
function countSetBits(num: number): number {
let count: number = 0;
while (num) {
count += num & 1;
num >>= 1;
}
return count;
}
const bitsCount: number = countSetBits(13);
console.log(Number of set bits in 13: ${bitsCount});
Bitwise Zero-Fill Right Shift Operator (>>>)
The zero-fill right shift operator is similar to the right shift operator but fills the empty positions with zeros, regardless of the sign bit.
const result: number = -5 >>> 1; // Binary: -1011 >>> 1
console.log(result); // Output: 2147483645
Operator Precedence in TypeScript
Basic understanding of operator precedence is essential for correctly interpreting the results of expressions involving multiple operators. TypeScript, like JavaScript, adheres to a set of rules that determine the order in which operators are evaluated. Here is a brief overview of TypeScript bitwise operator precedence, from highest to lowest:
- NOT Operator (~)
- Shift Operators (<<, >> and >>>)
- AND Operator (&)
- XOR Operator (^)
- OR Operator (|)
Let’s explore this through an example:
let result:number = 5 & 3 | 1 << 2;
console.log(result);
In this example, the bitwise AND (&) has a higher precedence than bitwise OR (|). The left shift (<<) has a higher precedence than both AND and OR.
Understanding operator precedence ensures that the expression is evaluated in the intended order, preventing unexpected results. However, you can use parentheses to alter the order of operations:
let result:number = 5 & (3 | 1) << 2;
console.log(result);
In this example, due to the use of parentheses, the OR (|) operation is performed first, followed by the left shift (<<), and then, finally, the AND (&). It is always advisable to use parentheses to clarify your intent, and to avoid errors.
JavaScript Bitwise Operators
For further information, kindly refer to the JavaScript Bitwise Operators. Everything discussed on that page is also applicable in the context of TypeScript.
Conclusion
In conclusion, TypeScript bitwise operators provide a powerful set of tools for manipulating binary data at a fundamental level. Understanding and utilizing these operators can lead to more efficient code, especially in scenarios where low-level bit manipulation is required.
As you explore TypeScript bitwise operators further, consider their applications in scenarios like bitwise shifting, setting flags, and optimizing data storage.