# Data Representation — Binary, Hex, Two's Complement, Overflow and IEEE 754 Floating Point

Source: https://skills101.in/learn/coa/data-representation-ieee-754 — Skills101 free tutorial (Computer Organisation & Architecture (COA)). Updated 2026-11-09.

Inside the computer everything is **bits**. How those bits are interpreted — unsigned, signed, floating-point, character — is decided by the representation. Exams love these conversions, and real bugs (integer overflow, `0.1 + 0.2 != 0.3`) come straight from them.

## 1. Binary and hexadecimal

Each binary digit is a power of 2. `1011₂ = 8 + 0 + 2 + 1 = 11`. Hexadecimal groups **4 bits** into one digit (0–9, A–F), which is why memory addresses and colours are written in hex.

```python
n = 202
print("binary:", bin(n), "| hex:", hex(n), "| octal:", oct(n))
print("1011 0110 as decimal:", int("10110110", 2))
print("0xCA as decimal:", int("CA", 16))
print("hex digit groups of 11001010:", "1100 ->", hex(0b1100), "| 1010 ->", hex(0b1010))
```

```text
binary: 0b11001010 | hex: 0xca | octal: 0o312
1011 0110 as decimal: 182
0xCA as decimal: 202
hex digit groups of 11001010: 1100 -> 0xc | 1010 -> 0xa
```

## 2. Signed numbers: three ways

How do we store −5 in 8 bits?

| Method | +5 | −5 | Zeros | Range (8 bits) |
|---|---|---|---|---|
| Sign-magnitude | `0000 0101` | `1000 0101` | two (+0, −0) | −127 to +127 |
| 1's complement (flip all bits) | `0000 0101` | `1111 1010` | two | −127 to +127 |
| **2's complement** (flip + 1) | `0000 0101` | `1111 1011` | **one** | **−128 to +127** |

Every modern CPU uses **2's complement**: one zero, and addition/subtraction use the **same adder circuit** for signed and unsigned numbers.

![Two's complement of 5 in 8 bits: start with 00000101, invert every bit to get 11111010, add 1 to get 11111011, which represents minus 5; the leftmost bit has weight minus 128](https://skills101.in/learn-img/coa/twos-complement.svg)

A neat way to read a 2's complement number: the **most significant bit has negative weight**. `1111 1011` = −128 + 64 + 32 + 16 + 8 + 0 + 2 + 1 = **−5**.

```python
def to_twos(value, bits=8):
    return format(value & (2 ** bits - 1), f"0{bits}b")

def from_twos(bitstr):
    v = int(bitstr, 2)
    return v - 2 ** len(bitstr) if bitstr[0] == "1" else v

for v in [5, -5, -1, 127, -128]:
    b = to_twos(v)
    print(f"{v:5} -> {b} -> back to {from_twos(b)}")
```

```text
    5 -> 00000101 -> back to 5
   -5 -> 11111011 -> back to -5
   -1 -> 11111111 -> back to -1
  127 -> 01111111 -> back to 127
 -128 -> 10000000 -> back to -128
```

**Range of n-bit 2's complement:** −2ⁿ⁻¹ to 2ⁿ⁻¹ − 1. For 8 bits: −128 to 127; 16 bits: −32,768 to 32,767; 32 bits: about ±2.1 billion.

## 3. Overflow

If the true result doesn't fit in the range, the stored result wraps around — **overflow**. Rule for 2's complement addition: **overflow happens only when two numbers of the same sign give a result of the opposite sign** (equivalently, carry into the sign bit ≠ carry out of it).

```python
def add8(a, b):
    raw = (a + b) & 0xFF
    result = raw - 256 if raw >= 128 else raw
    overflow = (a >= 0) == (b >= 0) and (result >= 0) != (a >= 0)
    return result, overflow

for a, b in [(100, 20), (100, 50), (-100, -50), (100, -50)]:
    r, ov = add8(a, b)
    print(f"{a:5} + {b:4} = {r:5}  overflow={ov}")
```

```text
  100 +   20 =   120  overflow=False
  100 +   50 =  -106  overflow=True
 -100 +  -50 =   106  overflow=True
  100 +  -50 =    50  overflow=False
```

`100 + 50` "became" −106 in 8 bits. Real bugs like this have crashed rockets and frozen games; languages like Java silently wrap `int` the same way at 32 bits.

## 4. IEEE 754 floating point

Real numbers use scientific notation in binary: **(−1)^sign × 1.mantissa × 2^(exponent − bias)**.

**Single precision (32 bits):** 1 sign bit, **8 exponent bits** (bias **127**), **23 fraction (mantissa) bits**. Double precision: 1 + 11 (bias 1023) + 52.

![IEEE 754 single precision layout: 1 sign bit, 8 exponent bits stored with a bias of 127, and 23 fraction bits with an implied leading 1](https://skills101.in/learn-img/coa/ieee754.svg)

**Worked example: −6.75**

1. Binary: 6.75 = `110.11₂`
2. Normalise: `1.1011 × 2²`
3. Sign = 1 (negative)
4. Exponent = 2 + 127 = 129 = `1000 0001`
5. Fraction = bits after the point: `1011` followed by zeros

Let Python confirm it bit by bit:

```python
import struct

def ieee754(x):
    bits = format(struct.unpack(">I", struct.pack(">f", x))[0], "032b")
    sign, exp, frac = bits[0], bits[1:9], bits[9:]
    print(f"{x:>8}: {sign} {exp} {frac}  (hex {hex(int(bits, 2))})")
    e = int(exp, 2)
    value = (-1) ** int(sign) * (1 + int(frac, 2) / 2 ** 23) * 2 ** (e - 127)
    print(f"          exponent {e} - 127 = {e - 127}, decoded back = {value}")

ieee754(-6.75)
ieee754(0.1)
```

```text
   -6.75: 1 10000001 10110000000000000000000  (hex 0xc0d80000)
          exponent 129 - 127 = 2, decoded back = -6.75
     0.1: 0 01111011 10011001100110011001101  (hex 0x3dcccccd)
          exponent 123 - 127 = -4, decoded back = 0.10000000149011612
```

`0.1` has no exact binary representation (like 1/3 in decimal), so the stored value is very slightly off — the root of `0.1 + 0.2 != 0.3` in every language.

**Special values:**

| Exponent bits | Fraction | Meaning |
|---|---|---|
| all 0 | 0 | ±0 |
| all 0 | ≠ 0 | denormal (tiny numbers) |
| all 1 | 0 | ±∞ |
| all 1 | ≠ 0 | NaN (not a number) |

## 5. Characters

- **ASCII**: 7 bits, 128 characters (`'A'` = 65).
- **Unicode / UTF-8**: every character in every script; UTF-8 uses 1 byte for ASCII and 2–4 bytes for others — Hindi letters take 3 bytes each.

```python
for ch in ["A", "₹", "क"]:
    print(ch, "code point", ord(ch), "UTF-8 bytes:", len(ch.encode("utf-8")))
```

```text
A code point 65 UTF-8 bytes: 1
₹ code point 8377 UTF-8 bytes: 3
क code point 2325 UTF-8 bytes: 3
```

## Common mistakes

- Forgetting to add 1 when taking 2's complement.
- Using range −127..127 for 8-bit 2's complement (it's −128..127).
- Forgetting the bias (127) or the implied leading 1 in IEEE 754.
- Declaring overflow when adding numbers of **opposite** signs (impossible in 2's complement).

## Quick recap

- Hex = groups of 4 bits.
- **2's complement** = invert + 1; MSB has weight −2ⁿ⁻¹; range −2ⁿ⁻¹ … 2ⁿ⁻¹−1; one zero.
- Overflow: same-sign operands, opposite-sign result.
- **IEEE 754 single**: 1 | 8 (bias 127) | 23, value = (−1)ˢ × 1.f × 2^(e−127).
- 0.1 isn't exact in binary; UTF-8 uses 1–4 bytes per character.


Practice quiz and free certificate: https://skills101.in/learn/coa/data-representation-ieee-754