How Computers Store Numbers: Binary, Hex and Why 0.1 + 0.2 Isn't 0.3

Bits, bytes, binary and hexadecimal explained simply, why integers have limits, and why decimal fractions like 0.1 are stored approximately, with a practical rule for money.

Free preview · 2 of 3 free left
Topic: Foundations Guide beginner 7 min read

Why this matters

Sooner or later every programmer meets a number that "does the wrong thing": a total that is off by a tiny amount, a counter that suddenly goes negative, a colour written as #FF8800. All of these come from one fact: a computer stores numbers in a fixed number of binary digits. Knowing that one fact turns these from mysteries into things you can predict.

What you'll learn

How binary and hexadecimal work, why whole numbers have a largest value, why 0.1 + 0.2 is not exactly 0.3, and one practical rule for storing money.

Everything is bits

A bit is a 0 or a 1, because a circuit can be off or on. A group of 8 bits is a byte. Binary counting works like decimal, but with two digits instead of ten. Each position is worth double the one to its right: 1, 2, 4, 8, 16, 32, 64, 128. So 1101 means 8 + 4 + 0 + 1 = 13. Eight bits can make 256 different patterns, the numbers 0 to 255.

Hexadecimal is just shorthand

Long strings of 0s and 1s are hard to read. Hexadecimal (base 16) uses the digits 0 to 9 and then A to F for 10 to 15. One hex digit stands for exactly four bits, so one byte is always two hex digits. FF is 15 × 16 + 15 = 255, the largest byte. That is why web colours look like #FF8800: three bytes, one each for red, green and blue.

Whole numbers have limits

A whole number is stored in a fixed number of bits. With 8 bits you can store 0 to 255, or if negatives are allowed, -128 to 127. Add 1 to the largest value and it overflows: it wraps around, or the program stops, depending on the language. Common sizes are 8, 16, 32 and 64 bits. A 32-bit signed integer tops out at 2,147,483,647, which has surprised many systems that counted something for long enough. Some languages, such as Python, quietly switch to bigger storage when needed, but many do not.

Fractions are stored approximately

Numbers with a fractional part are usually stored as floating point, a binary version of scientific notation. The catch is that binary can only write fractions whose denominator is a power of 2 exactly, such as 0.5 or 0.25. In decimal, 1/3 is 0.3333... forever and can never be written exactly. In the same way, 0.1 is a repeating pattern in binary and is cut off at some point. Add 0.1 and 0.2 and the tiny errors show up:

>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False

This is not a bug in Python or JavaScript. It is how floating point works in nearly every language. The error is tiny, but an == comparison does not forgive tiny errors.

Two practical rules

Try it yourself

In Python, bin(13) gives '0b1101' and hex(255) gives '0xff'. Try bin(255), then int("1010", 2), then 0.1 + 0.2, then round(0.1 + 0.2, 2) == 0.3. Finally, work out by hand: what does 1010 in binary equal, and what is 3F in decimal? (10, and 3 × 16 + 15 = 63.)

What's next

If the idea of a variable as a box with a fixed size feels new, read Your First Program: Understanding Before Memorizing. For where this fits in the bigger picture, read What Computer Science Actually Is.

Continue learning

Guide

What Computer Science Actually Is (and What It Isn't)

An honest picture of what a computer science degree really is before you start — problem-solving over memorization, why it's not just 'learning to code', and how to set the right expectations for four years.

Guide

Your First Program: Understanding Before Memorizing

Why memorizing syntax is the slow road and understanding what each line does is the fast one — how to read your first programs so the knowledge sticks.

← Back to Guides

Next → How DNS Resolution Actually Works What actually happens between typing a hostname and getting an IP address back — the lookup chain, caching layers, and why DNS is so often the first suspect in an outage.