Bitwise Operator

From bibbleWiki
Jump to navigation Jump to search

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:

  1. Bitwise Logic Operators
  2. Bitwise Shift Operators
  3. 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.

Logical Right Shift in C and C++

C and C++ do not provide a dedicated logical right shift operator for signed values. The operator >> performs an arithmetic right shift on signed types and a logical right shift on unsigned types.

To force a logical right shift, cast the value to an unsigned type:

 int i = -10;
 unsigned x = (unsigned)i >> 1;

Casting to unsigned causes >> to treat the bits as an unsigned integer, so zeros are shifted in from the left.

Without the cast, >> performs an arithmetic shift and preserves the sign bit:

 int x = i >> 1;   // arithmetic shift, sign bit copied

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.