Bitwise Operator
Introduction
I do not ever retain information so thought I would write this down for next time I forget
Two's Compliment
This is a mysterious word, but like decimal is a way to store numbers, Two's Compliment is a way to signed integers.
In this system, the MSB acts as the sign bit:
0 = positive, 1 = negative.
Signed vs Unsigned Values
Bits by themselves have no meaning. A sequence like:
11101000
is just eight bits. The type that holds those bits decides how they are interpreted.
Unsigned Types
Unsigned types treat the bits as a positive integer.
Example (8‑bit):
11101000 = 232
Unsigned values never represent negative numbers.
Signed Types
Signed types use the most significant bit (MSB left hand side) as a sign indicator using two's complement.
Example (8‑bit):
11101000 = −24
The bit pattern is the same as the unsigned example, but the type interprets it differently.
Why This Matters for Bitwise Operations
Right‑shift behaviour depends on whether the value is signed or unsigned:
- Signed types use an arithmetic right shift (>>), which preserves the sign bit.
- Unsigned types use a logical right shift (>>), which always shifts in zeros.
- Some languages provide logical right shift explicitly (>>>), which always shifts in zeros regardless of sign.
Key Idea
Bits are not inherently signed or unsigned. The type determines how the bits are interpreted and how operators behave.
Bitwise Operations Overview
Bitwise operations fall into three major groups:
- Bitwise Logic Operators
- Bitwise Shift Operators
- Bit Rotation Operators
These operations work directly on the binary representation of integers.
1. Bitwise Logic Operators
- AND ( & )
A result bit is 1 only if both input bits are 1.
- 0b1100 & 0b1010 = 0b1000
- OR ( | )
A result bit is 1 if either input bit is 1.
- 0b1100 | 0b1010 = 0b1110
- XOR ( ^ )
A result bit is 1 if the input bits are different. A result bit is 0 if the input bits are the same.
- 0b1100 ^ 0b1010 = 0b0110
- NOT ( ~ or ! )
1 becomes 0, and 0 becomes 1.
- ~0b00001111 = 0b11110000
2. Bitwise Shift Operators
Bitwise shifts move bits left or right. The important difference is what gets inserted into the leftmost bit when shifting right.
(Arithmetic) Left Shift ( << )
Shifts all bits to the left by n positions. Zeros are always shifted in from the right.
Example:
0001 << 2 = 0100
This is equivalent to multiplying by 2ⁿ for unsigned values.
(Arithmetic) Right Shift ( >> )
Shifts all bits to the right by n positions. The new leftmost bit is filled with the original MSB (the sign bit).
- If the value is positive (MSB = 0), zeros are shifted in.
- If the value is negative (MSB = 1), ones are shifted in.
This preserves the sign of the number.
Example (signed):
1110 1000 >> 3 = 1111 0100
Logical Right Shift ( >>> )
Shifts all bits to the right by n positions. The new leftmost bit is always 0, regardless of sign.
This treats the value as an unsigned bit pattern.
Example:
1110 1000 >>> 3 = 0001 1101
Only available in TypeScript/JavaScript. In a language which doe not support it you can do in C++
int i = -10; unsigned x = (unsigned)i >> n;
Casting to unsigned forces i to be treated as an unsigned and therefore the MSB is used e.g. 0b1010 is now treated as 0b11010
3. Bit Rotation Operators
- Rotate Left (ROL)
- ROL(0b1001, 1) = 0b0011
- Rotate Right (ROR)
- ROR(0b1001, 1) = 0b1100
Note: Only Rust, C++20, and C# provide built‑in rotate functions.
Language Support Table
| Operation | Rust | C | C++ | C# | TypeScript |
|---|---|---|---|---|---|
| AND ( & ) | ✔ | ✔ | ✔ | ✔ | ✔ |
| ) | ✔ | ✔ | ✔ | ✔ | ✔ |
| XOR ( ^ ) | ✔ | ✔ | ✔ | ✔ | ✔ |
| NOT ( ~ / ! ) | ! for ints | ~ | ~ | ~ | ~ |
| Left Shift ( << ) | ✔ | ✔ | ✔ | ✔ | ✔ |
| Right Shift ( >> ) | ✔ | ✔ | ✔ | ✔ | ✔ |
| Logical Right Shift ( >>> ) | ✘ | ✘ | ✘ | ✘ | ✔ |
| Rotate Left | rotate_left() | ✘ | std::rotl | RotateLeft | ✘ |
| Rotate Right | rotate_right() | ✘ | std::rotr | RotateRight | ✘ |
Language Notes
Rust
- Right shift is arithmetic for signed integers, logical for unsigned.
- Bitwise NOT uses ! instead of ~.
- Provides built‑in rotate_left() and rotate_right().
C
- Right shift of signed integers is implementation-defined.
- No built‑in rotate operations.
C++
- C++20 adds std::rotl and std::rotr.
- Right shift of signed integers is implementation-defined (same as C).
C#
- Right shift is arithmetic for signed, logical for unsigned.
- Provides BitOperations.RotateLeft/Right.
TypeScript
- Has both arithmetic (>>) and logical (>>>) right shift.
- No built‑in rotate; must be implemented manually.



